jubilant-funicular
CImg.h
1 /*
2  #
3  # File : CImg.h
4  # ( C++ header file )
5  #
6  # Description : The C++ Template Image Processing Toolkit.
7  # This file is the main component of the CImg Library project.
8  # ( http://cimg.eu )
9  #
10  # Project manager : David Tschumperle.
11  # ( http://tschumperle.users.greyc.fr/ )
12  #
13  # A complete list of contributors is available in file 'README.txt'
14  # distributed within the CImg package.
15  #
16  # Licenses : This file is 'dual-licensed', you have to choose one
17  # of the two licenses below to apply.
18  #
19  # CeCILL-C
20  # The CeCILL-C license is close to the GNU LGPL.
21  # ( http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html )
22  #
23  # or CeCILL v2.1
24  # The CeCILL license is compatible with the GNU GPL.
25  # ( http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.html )
26  #
27  # This software is governed either by the CeCILL or the CeCILL-C license
28  # under French law and abiding by the rules of distribution of free software.
29  # You can use, modify and or redistribute the software under the terms of
30  # the CeCILL or CeCILL-C licenses as circulated by CEA, CNRS and INRIA
31  # at the following URL: "http://www.cecill.info".
32  #
33  # As a counterpart to the access to the source code and rights to copy,
34  # modify and redistribute granted by the license, users are provided only
35  # with a limited warranty and the software's author, the holder of the
36  # economic rights, and the successive licensors have only limited
37  # liability.
38  #
39  # In this respect, the user's attention is drawn to the risks associated
40  # with loading, using, modifying and/or developing or reproducing the
41  # software by the user in light of its specific status of free software,
42  # that may mean that it is complicated to manipulate, and that also
43  # therefore means that it is reserved for developers and experienced
44  # professionals having in-depth computer knowledge. Users are therefore
45  # encouraged to load and test the software's suitability as regards their
46  # requirements in conditions enabling the security of their systems and/or
47  # data to be ensured and, more generally, to use and operate it in the
48  # same conditions as regards security.
49  #
50  # The fact that you are presently reading this means that you have had
51  # knowledge of the CeCILL and CeCILL-C licenses and that you accept its terms.
52  #
53 */
54 
55 // Set version number of the library.
56 #ifndef cimg_version
57 #define cimg_version 222
58 
59 /*-----------------------------------------------------------
60  #
61  # Test and possibly auto-set CImg configuration variables
62  # and include required headers.
63  #
64  # If you find that the default configuration variables are
65  # not adapted to your system, you can override their values
66  # before including the header file "CImg.h"
67  # (use the #define directive).
68  #
69  ------------------------------------------------------------*/
70 
71 // Include standard C++ headers.
72 // This is the minimal set of required headers to make CImg-based codes compile.
73 #include <cstdio>
74 #include <cstdlib>
75 #include <cstdarg>
76 #include <cstring>
77 #include <cmath>
78 #include <cfloat>
79 #include <climits>
80 #include <ctime>
81 #include <exception>
82 #include <algorithm>
83 
84 // Detect/configure OS variables.
85 //
86 // Define 'cimg_OS' to: '0' for an unknown OS (will try to minize library dependencies).
87 // '1' for a Unix-like OS (Linux, Solaris, BSD, MacOSX, Irix, ...).
88 // '2' for Microsoft Windows.
89 // (auto-detection is performed if 'cimg_OS' is not set by the user).
90 #ifndef cimg_OS
91 #if defined(unix) || defined(__unix) || defined(__unix__) \
92  || defined(linux) || defined(__linux) || defined(__linux__) \
93  || defined(sun) || defined(__sun) \
94  || defined(BSD) || defined(__OpenBSD__) || defined(__NetBSD__) \
95  || defined(__FreeBSD__) || defined (__DragonFly__) \
96  || defined(sgi) || defined(__sgi) \
97  || defined(__MACOSX__) || defined(__APPLE__) \
98  || defined(__CYGWIN__)
99 #define cimg_OS 1
100 #elif defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \
101  || defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
102 #define cimg_OS 2
103 #else
104 #define cimg_OS 0
105 #endif
106 #elif !(cimg_OS==0 || cimg_OS==1 || cimg_OS==2)
107 #error CImg Library: Invalid configuration variable 'cimg_OS'.
108 #error (correct values are '0 = unknown OS', '1 = Unix-like OS', '2 = Microsoft Windows').
109 #endif
110 #ifndef cimg_date
111 #define cimg_date __DATE__
112 #endif
113 #ifndef cimg_time
114 #define cimg_time __TIME__
115 #endif
116 
117 // Disable silly warnings on some Microsoft VC++ compilers.
118 #ifdef _MSC_VER
119 #pragma warning(push)
120 #pragma warning(disable:4127)
121 #pragma warning(disable:4244)
122 #pragma warning(disable:4311)
123 #pragma warning(disable:4312)
124 #pragma warning(disable:4319)
125 #pragma warning(disable:4512)
126 #pragma warning(disable:4571)
127 #pragma warning(disable:4640)
128 #pragma warning(disable:4706)
129 #pragma warning(disable:4710)
130 #pragma warning(disable:4800)
131 #pragma warning(disable:4804)
132 #pragma warning(disable:4820)
133 #pragma warning(disable:4996)
134 
135 #ifndef _CRT_SECURE_NO_DEPRECATE
136 #define _CRT_SECURE_NO_DEPRECATE 1
137 #endif
138 #ifndef _CRT_SECURE_NO_WARNINGS
139 #define _CRT_SECURE_NO_WARNINGS 1
140 #endif
141 #ifndef _CRT_NONSTDC_NO_DEPRECATE
142 #define _CRT_NONSTDC_NO_DEPRECATE 1
143 #endif
144 #endif
145 
146 // Define correct string functions for each compiler and OS.
147 #if cimg_OS==2 && defined(_MSC_VER)
148 #define cimg_sscanf std::sscanf
149 #define cimg_sprintf std::sprintf
150 #define cimg_snprintf cimg::_snprintf
151 #define cimg_vsnprintf cimg::_vsnprintf
152 #else
153 #include <stdio.h>
154 #if defined(__MACOSX__) || defined(__APPLE__)
155 #define cimg_sscanf cimg::_sscanf
156 #define cimg_sprintf cimg::_sprintf
157 #define cimg_snprintf cimg::_snprintf
158 #define cimg_vsnprintf cimg::_vsnprintf
159 #else
160 #define cimg_sscanf std::sscanf
161 #define cimg_sprintf std::sprintf
162 #define cimg_snprintf snprintf
163 #define cimg_vsnprintf vsnprintf
164 #endif
165 #endif
166 
167 // Include OS-specific headers.
168 #if cimg_OS==1
169 #include <sys/types.h>
170 #include <sys/time.h>
171 #include <sys/stat.h>
172 #include <unistd.h>
173 #include <dirent.h>
174 #include <fnmatch.h>
175 #elif cimg_OS==2
176 #ifndef std_fopen
177 #define std_fopen cimg::win_fopen
178 #endif
179 #ifndef NOMINMAX
180 #define NOMINMAX
181 #endif
182 #ifndef WIN32_LEAN_AND_MEAN
183 #define WIN32_LEAN_AND_MEAN
184 #endif
185 #include <windows.h>
186 #ifndef _WIN32_IE
187 #define _WIN32_IE 0x0400
188 #endif
189 #include <shlobj.h>
190 #include <process.h>
191 #include <io.h>
192 #endif
193 
194 // Look for C++11 features.
195 #ifndef cimg_use_cpp11
196 #if __cplusplus>201100
197 #define cimg_use_cpp11 1
198 #else
199 #define cimg_use_cpp11 0
200 #endif
201 #endif
202 #if cimg_use_cpp11==1
203 #include <initializer_list>
204 #include <utility>
205 #endif
206 
207 // Convenient macro to define pragma
208 #ifdef _MSC_VER
209 #define cimg_pragma(x) __pragma(x)
210 #else
211 #define cimg_pragma(x) _Pragma(#x)
212 #endif
213 
214 // Define own types 'cimg_long/ulong' and 'cimg_int64/uint64' to ensure portability.
215 // ( constrained to 'sizeof(cimg_ulong/cimg_long) = sizeof(void*)' and 'sizeof(cimg_int64/cimg_uint64)=8' ).
216 #if cimg_OS==2
217 
218 #define cimg_uint64 unsigned __int64
219 #define cimg_int64 __int64
220 #define cimg_ulong UINT_PTR
221 #define cimg_long INT_PTR
222 #ifdef _MSC_VER
223 #define cimg_fuint64 "%I64u"
224 #define cimg_fint64 "%I64d"
225 #else
226 #define cimg_fuint64 "%llu"
227 #define cimg_fint64 "%lld"
228 #endif
229 
230 #else
231 
232 #if UINTPTR_MAX==0xffffffff || defined(__arm__) || defined(_M_ARM) || ((ULONG_MAX)==(UINT_MAX))
233 #define cimg_uint64 unsigned long long
234 #define cimg_int64 long long
235 #define cimg_fuint64 "%llu"
236 #define cimg_fint64 "%lld"
237 #else
238 #define cimg_uint64 unsigned long
239 #define cimg_int64 long
240 #define cimg_fuint64 "%lu"
241 #define cimg_fint64 "%ld"
242 #endif
243 
244 #if defined(__arm__) || defined(_M_ARM)
245 #define cimg_ulong unsigned long long
246 #define cimg_long long long
247 #else
248 #define cimg_ulong unsigned long
249 #define cimg_long long
250 #endif
251 
252 #endif
253 
254 // Configure filename separator.
255 //
256 // Filename separator is set by default to '/', except for Windows where it is '\'.
257 #ifndef cimg_file_separator
258 #if cimg_OS==2
259 #define cimg_file_separator '\\'
260 #else
261 #define cimg_file_separator '/'
262 #endif
263 #endif
264 
265 // Configure verbosity of output messages.
266 //
267 // Define 'cimg_verbosity' to: '0' to hide library messages (quiet mode).
268 // '1' to output library messages on the console.
269 // '2' to output library messages on a basic dialog window (default behavior).
270 // '3' to do as '1' + add extra warnings (may slow down the code!).
271 // '4' to do as '2' + add extra warnings (may slow down the code!).
272 //
273 // Define 'cimg_strict_warnings' to replace warning messages by exception throwns.
274 //
275 // Define 'cimg_use_vt100' to allow output of color messages on VT100-compatible terminals.
276 #ifndef cimg_verbosity
277 #if cimg_OS==2
278 #define cimg_verbosity 2
279 #else
280 #define cimg_verbosity 1
281 #endif
282 #elif !(cimg_verbosity==0 || cimg_verbosity==1 || cimg_verbosity==2 || cimg_verbosity==3 || cimg_verbosity==4)
283 #error CImg Library: Configuration variable 'cimg_verbosity' is badly defined.
284 #error (should be { 0=quiet | 1=console | 2=dialog | 3=console+warnings | 4=dialog+warnings }).
285 #endif
286 
287 // Configure display framework.
288 //
289 // Define 'cimg_display' to: '0' to disable display capabilities.
290 // '1' to use the X-Window framework (X11).
291 // '2' to use the Microsoft GDI32 framework.
292 #ifndef cimg_display
293 #if cimg_OS==0
294 #define cimg_display 0
295 #elif cimg_OS==1
296 #define cimg_display 1
297 #elif cimg_OS==2
298 #define cimg_display 2
299 #endif
300 #elif !(cimg_display==0 || cimg_display==1 || cimg_display==2)
301 #error CImg Library: Configuration variable 'cimg_display' is badly defined.
302 #error (should be { 0=none | 1=X-Window (X11) | 2=Microsoft GDI32 }).
303 #endif
304 
305 // Configure the 'abort' signal handler (does nothing by default).
306 // A typical signal handler can be defined in your own source like this:
307 // #define cimg_abort_test if (is_abort) throw CImgAbortException("")
308 //
309 // where 'is_abort' is a boolean variable defined somewhere in your code and reachable in the method.
310 // 'cimg_abort_test2' does the same but is called more often (in inner loops).
311 #if defined(cimg_abort_test) && defined(cimg_use_openmp)
312 
313 // Define abort macros to be used with OpenMP.
314 #ifndef _cimg_abort_init_omp
315 #define _cimg_abort_init_omp bool _cimg_abort_go_omp = true; cimg::unused(_cimg_abort_go_omp)
316 #endif
317 #ifndef _cimg_abort_try_omp
318 #define _cimg_abort_try_omp if (_cimg_abort_go_omp) try
319 #endif
320 #ifndef _cimg_abort_catch_omp
321 #define _cimg_abort_catch_omp catch (CImgAbortException&) { cimg_pragma(omp atomic) _cimg_abort_go_omp&=false; }
322 #endif
323 #ifdef cimg_abort_test2
324 #ifndef _cimg_abort_try_omp2
325 #define _cimg_abort_try_omp2 _cimg_abort_try_omp
326 #endif
327 #ifndef _cimg_abort_catch_omp2
328 #define _cimg_abort_catch_omp2 _cimg_abort_catch_omp
329 #endif
330 #ifndef _cimg_abort_catch_fill_omp
331 #define _cimg_abort_catch_fill_omp \
332  catch (CImgException& e) { cimg_pragma(omp critical(abort)) CImg<charT>::string(e._message).move_to(is_error); \
333  cimg_pragma(omp atomic) _cimg_abort_go_omp&=false; }
334 #endif
335 #endif
336 #endif
337 
338 #ifndef _cimg_abort_init_omp
339 #define _cimg_abort_init_omp
340 #endif
341 #ifndef _cimg_abort_try_omp
342 #define _cimg_abort_try_omp
343 #endif
344 #ifndef _cimg_abort_catch_omp
345 #define _cimg_abort_catch_omp
346 #endif
347 #ifndef _cimg_abort_try_omp2
348 #define _cimg_abort_try_omp2
349 #endif
350 #ifndef _cimg_abort_catch_omp2
351 #define _cimg_abort_catch_omp2
352 #endif
353 #ifndef _cimg_abort_catch_fill_omp
354 #define _cimg_abort_catch_fill_omp
355 #endif
356 #ifndef cimg_abort_init
357 #define cimg_abort_init
358 #endif
359 #ifndef cimg_abort_test
360 #define cimg_abort_test
361 #endif
362 #ifndef cimg_abort_test2
363 #define cimg_abort_test2
364 #endif
365 #ifndef std_fopen
366 #define std_fopen std::fopen
367 #endif
368 
369 // Include display-specific headers.
370 #if cimg_display==1
371 #include <X11/Xlib.h>
372 #include <X11/Xutil.h>
373 #include <X11/keysym.h>
374 #include <pthread.h>
375 #ifdef cimg_use_xshm
376 #include <sys/ipc.h>
377 #include <sys/shm.h>
378 #include <X11/extensions/XShm.h>
379 #endif
380 #ifdef cimg_use_xrandr
381 #include <X11/extensions/Xrandr.h>
382 #endif
383 #endif
384 #ifndef cimg_appname
385 #define cimg_appname "CImg"
386 #endif
387 
388 // Configure OpenMP support.
389 // (http://www.openmp.org)
390 //
391 // Define 'cimg_use_openmp' to enable OpenMP support.
392 //
393 // OpenMP directives may be used in a (very) few CImg functions to get
394 // advantages of multi-core CPUs.
395 #ifdef cimg_use_openmp
396 #include <omp.h>
397 #define cimg_pragma_openmp(p) cimg_pragma(omp p)
398 #else
399 #define cimg_pragma_openmp(p)
400 #endif
401 
402 // Configure OpenCV support.
403 // (http://opencv.willowgarage.com/wiki/)
404 //
405 // Define 'cimg_use_opencv' to enable OpenCV support.
406 //
407 // OpenCV library may be used to access images from cameras
408 // (see method 'CImg<T>::load_camera()').
409 #ifdef cimg_use_opencv
410 #ifdef True
411 #undef True
412 #define _cimg_redefine_True
413 #endif
414 #ifdef False
415 #undef False
416 #define _cimg_redefine_False
417 #endif
418 #include <cstddef>
419 #include "cv.h"
420 #include "highgui.h"
421 #endif
422 
423 // Configure LibPNG support.
424 // (http://www.libpng.org)
425 //
426 // Define 'cimg_use_png' to enable LibPNG support.
427 //
428 // PNG library may be used to get a native support of '.png' files.
429 // (see methods 'CImg<T>::{load,save}_png()'.
430 #ifdef cimg_use_png
431 extern "C" {
432 #include "png.h"
433 }
434 #endif
435 
436 // Configure LibJPEG support.
437 // (http://en.wikipedia.org/wiki/Libjpeg)
438 //
439 // Define 'cimg_use_jpeg' to enable LibJPEG support.
440 //
441 // JPEG library may be used to get a native support of '.jpg' files.
442 // (see methods 'CImg<T>::{load,save}_jpeg()').
443 #ifdef cimg_use_jpeg
444 extern "C" {
445 #include "jpeglib.h"
446 #include "setjmp.h"
447 }
448 #endif
449 
450 // Configure LibTIFF support.
451 // (http://www.libtiff.org)
452 //
453 // Define 'cimg_use_tiff' to enable LibTIFF support.
454 //
455 // TIFF library may be used to get a native support of '.tif' files.
456 // (see methods 'CImg[List]<T>::{load,save}_tiff()').
457 #ifdef cimg_use_tiff
458 extern "C" {
459 #define uint64 uint64_hack_
460 #define int64 int64_hack_
461 #include "tiffio.h"
462 #undef uint64
463 #undef int64
464 }
465 #endif
466 
467 // Configure LibMINC2 support.
468 // (http://en.wikibooks.org/wiki/MINC/Reference/MINC2.0_File_Format_Reference)
469 //
470 // Define 'cimg_use_minc2' to enable LibMINC2 support.
471 //
472 // MINC2 library may be used to get a native support of '.mnc' files.
473 // (see methods 'CImg<T>::{load,save}_minc2()').
474 #ifdef cimg_use_minc2
475 #include "minc_io_simple_volume.h"
476 #include "minc_1_simple.h"
477 #include "minc_1_simple_rw.h"
478 #endif
479 
480 // Configure Zlib support.
481 // (http://www.zlib.net)
482 //
483 // Define 'cimg_use_zlib' to enable Zlib support.
484 //
485 // Zlib library may be used to allow compressed data in '.cimgz' files
486 // (see methods 'CImg[List]<T>::{load,save}_cimg()').
487 #ifdef cimg_use_zlib
488 extern "C" {
489 #include "zlib.h"
490 }
491 #endif
492 
493 // Configure libcurl support.
494 // (http://curl.haxx.se/libcurl/)
495 //
496 // Define 'cimg_use_curl' to enable libcurl support.
497 //
498 // Libcurl may be used to get a native support of file downloading from the network.
499 // (see method 'cimg::load_network()'.)
500 #ifdef cimg_use_curl
501 #include "curl/curl.h"
502 #endif
503 
504 // Configure Magick++ support.
505 // (http://www.imagemagick.org/Magick++)
506 //
507 // Define 'cimg_use_magick' to enable Magick++ support.
508 //
509 // Magick++ library may be used to get a native support of various image file formats.
510 // (see methods 'CImg<T>::{load,save}()').
511 #ifdef cimg_use_magick
512 #include "Magick++.h"
513 #endif
514 
515 // Configure FFTW3 support.
516 // (http://www.fftw.org)
517 //
518 // Define 'cimg_use_fftw3' to enable libFFTW3 support.
519 //
520 // FFTW3 library may be used to efficiently compute the Fast Fourier Transform
521 // of image data, without restriction on the image size.
522 // (see method 'CImg[List]<T>::FFT()').
523 #ifdef cimg_use_fftw3
524 extern "C" {
525 #include "fftw3.h"
526 }
527 #endif
528 
529 // Configure LibBoard support.
530 // (http://libboard.sourceforge.net/)
531 //
532 // Define 'cimg_use_board' to enable Board support.
533 //
534 // Board library may be used to draw 3d objects in vector-graphics canvas
535 // that can be saved as '.ps' or '.svg' files afterwards.
536 // (see method 'CImg<T>::draw_object3d()').
537 #ifdef cimg_use_board
538 #include "Board.h"
539 #endif
540 
541 // Configure OpenEXR support.
542 // (http://www.openexr.com/)
543 //
544 // Define 'cimg_use_openexr' to enable OpenEXR support.
545 //
546 // OpenEXR library may be used to get a native support of '.exr' files.
547 // (see methods 'CImg<T>::{load,save}_exr()').
548 #ifdef cimg_use_openexr
549 #include "ImfRgbaFile.h"
550 #include "ImfInputFile.h"
551 #include "ImfChannelList.h"
552 #include "ImfMatrixAttribute.h"
553 #include "ImfArray.h"
554 #endif
555 
556 // Configure TinyEXR support.
557 // (https://github.com/syoyo/tinyexr)
558 //
559 // Define 'cimg_use_tinyexr' to enable TinyEXR support.
560 //
561 // TinyEXR is a small, single header-only library to load and save OpenEXR(.exr) images.
562 #ifdef cimg_use_tinyexr
563 #ifndef TINYEXR_IMPLEMENTATION
564 #define TINYEXR_IMPLEMENTATION
565 #endif
566 #include "tinyexr.h"
567 #endif
568 
569 // Lapack configuration.
570 // (http://www.netlib.org/lapack)
571 //
572 // Define 'cimg_use_lapack' to enable LAPACK support.
573 //
574 // Lapack library may be used in several CImg methods to speed up
575 // matrix computations (eigenvalues, inverse, ...).
576 #ifdef cimg_use_lapack
577 extern "C" {
578  extern void sgetrf_(int*, int*, float*, int*, int*, int*);
579  extern void sgetri_(int*, float*, int*, int*, float*, int*, int*);
580  extern void sgetrs_(char*, int*, int*, float*, int*, int*, float*, int*, int*);
581  extern void sgesvd_(char*, char*, int*, int*, float*, int*, float*, float*, int*, float*, int*, float*, int*, int*);
582  extern void ssyev_(char*, char*, int*, float*, int*, float*, float*, int*, int*);
583  extern void dgetrf_(int*, int*, double*, int*, int*, int*);
584  extern void dgetri_(int*, double*, int*, int*, double*, int*, int*);
585  extern void dgetrs_(char*, int*, int*, double*, int*, int*, double*, int*, int*);
586  extern void dgesvd_(char*, char*, int*, int*, double*, int*, double*, double*,
587  int*, double*, int*, double*, int*, int*);
588  extern void dsyev_(char*, char*, int*, double*, int*, double*, double*, int*, int*);
589  extern void dgels_(char*, int*,int*,int*,double*,int*,double*,int*,double*,int*,int*);
590  extern void sgels_(char*, int*,int*,int*,float*,int*,float*,int*,float*,int*,int*);
591 }
592 #endif
593 
594 // Check if min/max/PI macros are defined.
595 //
596 // CImg does not compile if macros 'min', 'max' or 'PI' are defined,
597 // because it redefines functions min(), max() and const variable PI in the cimg:: namespace.
598 // so it '#undef' these macros if necessary, and restore them to reasonable
599 // values at the end of this file.
600 #ifdef min
601 #undef min
602 #define _cimg_redefine_min
603 #endif
604 #ifdef max
605 #undef max
606 #define _cimg_redefine_max
607 #endif
608 #ifdef PI
609 #undef PI
610 #define _cimg_redefine_PI
611 #endif
612 
613 // Define 'cimg_library' namespace suffix.
614 //
615 // You may want to add a suffix to the 'cimg_library' namespace, for instance if you need to work
616 // with several versions of the library at the same time.
617 #ifdef cimg_namespace_suffix
618 #define __cimg_library_suffixed(s) cimg_library_##s
619 #define _cimg_library_suffixed(s) __cimg_library_suffixed(s)
620 #define cimg_library_suffixed _cimg_library_suffixed(cimg_namespace_suffix)
621 #else
622 #define cimg_library_suffixed cimg_library
623 #endif
624 
625 /*------------------------------------------------------------------------------
626  #
627  # Define user-friendly macros.
628  #
629  # These CImg macros are prefixed by 'cimg_' and can be used safely in your own
630  # code. They are useful to parse command line options, or to write image loops.
631  #
632  ------------------------------------------------------------------------------*/
633 
634 // Macros to define program usage, and retrieve command line arguments.
635 #define cimg_usage(usage) cimg_library_suffixed::cimg::option((char*)0,argc,argv,(char*)0,usage,false)
636 #define cimg_help(str) cimg_library_suffixed::cimg::option((char*)0,argc,argv,str,(char*)0)
637 #define cimg_option(name,defaut,usage) cimg_library_suffixed::cimg::option(name,argc,argv,defaut,usage)
638 
639 // Macros to define and manipulate local neighborhoods.
640 #define CImg_2x2(I,T) T I[4]; \
641  T& I##cc = I[0]; T& I##nc = I[1]; \
642  T& I##cn = I[2]; T& I##nn = I[3]; \
643  I##cc = I##nc = \
644  I##cn = I##nn = 0
645 
646 #define CImg_3x3(I,T) T I[9]; \
647  T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; \
648  T& I##pc = I[3]; T& I##cc = I[4]; T& I##nc = I[5]; \
649  T& I##pn = I[6]; T& I##cn = I[7]; T& I##nn = I[8]; \
650  I##pp = I##cp = I##np = \
651  I##pc = I##cc = I##nc = \
652  I##pn = I##cn = I##nn = 0
653 
654 #define CImg_4x4(I,T) T I[16]; \
655  T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; T& I##ap = I[3]; \
656  T& I##pc = I[4]; T& I##cc = I[5]; T& I##nc = I[6]; T& I##ac = I[7]; \
657  T& I##pn = I[8]; T& I##cn = I[9]; T& I##nn = I[10]; T& I##an = I[11]; \
658  T& I##pa = I[12]; T& I##ca = I[13]; T& I##na = I[14]; T& I##aa = I[15]; \
659  I##pp = I##cp = I##np = I##ap = \
660  I##pc = I##cc = I##nc = I##ac = \
661  I##pn = I##cn = I##nn = I##an = \
662  I##pa = I##ca = I##na = I##aa = 0
663 
664 #define CImg_5x5(I,T) T I[25]; \
665  T& I##bb = I[0]; T& I##pb = I[1]; T& I##cb = I[2]; T& I##nb = I[3]; T& I##ab = I[4]; \
666  T& I##bp = I[5]; T& I##pp = I[6]; T& I##cp = I[7]; T& I##np = I[8]; T& I##ap = I[9]; \
667  T& I##bc = I[10]; T& I##pc = I[11]; T& I##cc = I[12]; T& I##nc = I[13]; T& I##ac = I[14]; \
668  T& I##bn = I[15]; T& I##pn = I[16]; T& I##cn = I[17]; T& I##nn = I[18]; T& I##an = I[19]; \
669  T& I##ba = I[20]; T& I##pa = I[21]; T& I##ca = I[22]; T& I##na = I[23]; T& I##aa = I[24]; \
670  I##bb = I##pb = I##cb = I##nb = I##ab = \
671  I##bp = I##pp = I##cp = I##np = I##ap = \
672  I##bc = I##pc = I##cc = I##nc = I##ac = \
673  I##bn = I##pn = I##cn = I##nn = I##an = \
674  I##ba = I##pa = I##ca = I##na = I##aa = 0
675 
676 #define CImg_2x2x2(I,T) T I[8]; \
677  T& I##ccc = I[0]; T& I##ncc = I[1]; \
678  T& I##cnc = I[2]; T& I##nnc = I[3]; \
679  T& I##ccn = I[4]; T& I##ncn = I[5]; \
680  T& I##cnn = I[6]; T& I##nnn = I[7]; \
681  I##ccc = I##ncc = \
682  I##cnc = I##nnc = \
683  I##ccn = I##ncn = \
684  I##cnn = I##nnn = 0
685 
686 #define CImg_3x3x3(I,T) T I[27]; \
687  T& I##ppp = I[0]; T& I##cpp = I[1]; T& I##npp = I[2]; \
688  T& I##pcp = I[3]; T& I##ccp = I[4]; T& I##ncp = I[5]; \
689  T& I##pnp = I[6]; T& I##cnp = I[7]; T& I##nnp = I[8]; \
690  T& I##ppc = I[9]; T& I##cpc = I[10]; T& I##npc = I[11]; \
691  T& I##pcc = I[12]; T& I##ccc = I[13]; T& I##ncc = I[14]; \
692  T& I##pnc = I[15]; T& I##cnc = I[16]; T& I##nnc = I[17]; \
693  T& I##ppn = I[18]; T& I##cpn = I[19]; T& I##npn = I[20]; \
694  T& I##pcn = I[21]; T& I##ccn = I[22]; T& I##ncn = I[23]; \
695  T& I##pnn = I[24]; T& I##cnn = I[25]; T& I##nnn = I[26]; \
696  I##ppp = I##cpp = I##npp = \
697  I##pcp = I##ccp = I##ncp = \
698  I##pnp = I##cnp = I##nnp = \
699  I##ppc = I##cpc = I##npc = \
700  I##pcc = I##ccc = I##ncc = \
701  I##pnc = I##cnc = I##nnc = \
702  I##ppn = I##cpn = I##npn = \
703  I##pcn = I##ccn = I##ncn = \
704  I##pnn = I##cnn = I##nnn = 0
705 
706 #define cimg_get2x2(img,x,y,z,c,I,T) \
707  I[0] = (T)(img)(x,y,z,c), I[1] = (T)(img)(_n1##x,y,z,c), I[2] = (T)(img)(x,_n1##y,z,c), \
708  I[3] = (T)(img)(_n1##x,_n1##y,z,c)
709 
710 #define cimg_get3x3(img,x,y,z,c,I,T) \
711  I[0] = (T)(img)(_p1##x,_p1##y,z,c), I[1] = (T)(img)(x,_p1##y,z,c), I[2] = (T)(img)(_n1##x,_p1##y,z,c), \
712  I[3] = (T)(img)(_p1##x,y,z,c), I[4] = (T)(img)(x,y,z,c), I[5] = (T)(img)(_n1##x,y,z,c), \
713  I[6] = (T)(img)(_p1##x,_n1##y,z,c), I[7] = (T)(img)(x,_n1##y,z,c), I[8] = (T)(img)(_n1##x,_n1##y,z,c)
714 
715 #define cimg_get4x4(img,x,y,z,c,I,T) \
716  I[0] = (T)(img)(_p1##x,_p1##y,z,c), I[1] = (T)(img)(x,_p1##y,z,c), I[2] = (T)(img)(_n1##x,_p1##y,z,c), \
717  I[3] = (T)(img)(_n2##x,_p1##y,z,c), I[4] = (T)(img)(_p1##x,y,z,c), I[5] = (T)(img)(x,y,z,c), \
718  I[6] = (T)(img)(_n1##x,y,z,c), I[7] = (T)(img)(_n2##x,y,z,c), I[8] = (T)(img)(_p1##x,_n1##y,z,c), \
719  I[9] = (T)(img)(x,_n1##y,z,c), I[10] = (T)(img)(_n1##x,_n1##y,z,c), I[11] = (T)(img)(_n2##x,_n1##y,z,c), \
720  I[12] = (T)(img)(_p1##x,_n2##y,z,c), I[13] = (T)(img)(x,_n2##y,z,c), I[14] = (T)(img)(_n1##x,_n2##y,z,c), \
721  I[15] = (T)(img)(_n2##x,_n2##y,z,c)
722 
723 #define cimg_get5x5(img,x,y,z,c,I,T) \
724  I[0] = (T)(img)(_p2##x,_p2##y,z,c), I[1] = (T)(img)(_p1##x,_p2##y,z,c), I[2] = (T)(img)(x,_p2##y,z,c), \
725  I[3] = (T)(img)(_n1##x,_p2##y,z,c), I[4] = (T)(img)(_n2##x,_p2##y,z,c), I[5] = (T)(img)(_p2##x,_p1##y,z,c), \
726  I[6] = (T)(img)(_p1##x,_p1##y,z,c), I[7] = (T)(img)(x,_p1##y,z,c), I[8] = (T)(img)(_n1##x,_p1##y,z,c), \
727  I[9] = (T)(img)(_n2##x,_p1##y,z,c), I[10] = (T)(img)(_p2##x,y,z,c), I[11] = (T)(img)(_p1##x,y,z,c), \
728  I[12] = (T)(img)(x,y,z,c), I[13] = (T)(img)(_n1##x,y,z,c), I[14] = (T)(img)(_n2##x,y,z,c), \
729  I[15] = (T)(img)(_p2##x,_n1##y,z,c), I[16] = (T)(img)(_p1##x,_n1##y,z,c), I[17] = (T)(img)(x,_n1##y,z,c), \
730  I[18] = (T)(img)(_n1##x,_n1##y,z,c), I[19] = (T)(img)(_n2##x,_n1##y,z,c), I[20] = (T)(img)(_p2##x,_n2##y,z,c), \
731  I[21] = (T)(img)(_p1##x,_n2##y,z,c), I[22] = (T)(img)(x,_n2##y,z,c), I[23] = (T)(img)(_n1##x,_n2##y,z,c), \
732  I[24] = (T)(img)(_n2##x,_n2##y,z,c)
733 
734 #define cimg_get6x6(img,x,y,z,c,I,T) \
735  I[0] = (T)(img)(_p2##x,_p2##y,z,c), I[1] = (T)(img)(_p1##x,_p2##y,z,c), I[2] = (T)(img)(x,_p2##y,z,c), \
736  I[3] = (T)(img)(_n1##x,_p2##y,z,c), I[4] = (T)(img)(_n2##x,_p2##y,z,c), I[5] = (T)(img)(_n3##x,_p2##y,z,c), \
737  I[6] = (T)(img)(_p2##x,_p1##y,z,c), I[7] = (T)(img)(_p1##x,_p1##y,z,c), I[8] = (T)(img)(x,_p1##y,z,c), \
738  I[9] = (T)(img)(_n1##x,_p1##y,z,c), I[10] = (T)(img)(_n2##x,_p1##y,z,c), I[11] = (T)(img)(_n3##x,_p1##y,z,c), \
739  I[12] = (T)(img)(_p2##x,y,z,c), I[13] = (T)(img)(_p1##x,y,z,c), I[14] = (T)(img)(x,y,z,c), \
740  I[15] = (T)(img)(_n1##x,y,z,c), I[16] = (T)(img)(_n2##x,y,z,c), I[17] = (T)(img)(_n3##x,y,z,c), \
741  I[18] = (T)(img)(_p2##x,_n1##y,z,c), I[19] = (T)(img)(_p1##x,_n1##y,z,c), I[20] = (T)(img)(x,_n1##y,z,c), \
742  I[21] = (T)(img)(_n1##x,_n1##y,z,c), I[22] = (T)(img)(_n2##x,_n1##y,z,c), I[23] = (T)(img)(_n3##x,_n1##y,z,c), \
743  I[24] = (T)(img)(_p2##x,_n2##y,z,c), I[25] = (T)(img)(_p1##x,_n2##y,z,c), I[26] = (T)(img)(x,_n2##y,z,c), \
744  I[27] = (T)(img)(_n1##x,_n2##y,z,c), I[28] = (T)(img)(_n2##x,_n2##y,z,c), I[29] = (T)(img)(_n3##x,_n2##y,z,c), \
745  I[30] = (T)(img)(_p2##x,_n3##y,z,c), I[31] = (T)(img)(_p1##x,_n3##y,z,c), I[32] = (T)(img)(x,_n3##y,z,c), \
746  I[33] = (T)(img)(_n1##x,_n3##y,z,c), I[34] = (T)(img)(_n2##x,_n3##y,z,c), I[35] = (T)(img)(_n3##x,_n3##y,z,c)
747 
748 #define cimg_get7x7(img,x,y,z,c,I,T) \
749  I[0] = (T)(img)(_p3##x,_p3##y,z,c), I[1] = (T)(img)(_p2##x,_p3##y,z,c), I[2] = (T)(img)(_p1##x,_p3##y,z,c), \
750  I[3] = (T)(img)(x,_p3##y,z,c), I[4] = (T)(img)(_n1##x,_p3##y,z,c), I[5] = (T)(img)(_n2##x,_p3##y,z,c), \
751  I[6] = (T)(img)(_n3##x,_p3##y,z,c), I[7] = (T)(img)(_p3##x,_p2##y,z,c), I[8] = (T)(img)(_p2##x,_p2##y,z,c), \
752  I[9] = (T)(img)(_p1##x,_p2##y,z,c), I[10] = (T)(img)(x,_p2##y,z,c), I[11] = (T)(img)(_n1##x,_p2##y,z,c), \
753  I[12] = (T)(img)(_n2##x,_p2##y,z,c), I[13] = (T)(img)(_n3##x,_p2##y,z,c), I[14] = (T)(img)(_p3##x,_p1##y,z,c), \
754  I[15] = (T)(img)(_p2##x,_p1##y,z,c), I[16] = (T)(img)(_p1##x,_p1##y,z,c), I[17] = (T)(img)(x,_p1##y,z,c), \
755  I[18] = (T)(img)(_n1##x,_p1##y,z,c), I[19] = (T)(img)(_n2##x,_p1##y,z,c), I[20] = (T)(img)(_n3##x,_p1##y,z,c), \
756  I[21] = (T)(img)(_p3##x,y,z,c), I[22] = (T)(img)(_p2##x,y,z,c), I[23] = (T)(img)(_p1##x,y,z,c), \
757  I[24] = (T)(img)(x,y,z,c), I[25] = (T)(img)(_n1##x,y,z,c), I[26] = (T)(img)(_n2##x,y,z,c), \
758  I[27] = (T)(img)(_n3##x,y,z,c), I[28] = (T)(img)(_p3##x,_n1##y,z,c), I[29] = (T)(img)(_p2##x,_n1##y,z,c), \
759  I[30] = (T)(img)(_p1##x,_n1##y,z,c), I[31] = (T)(img)(x,_n1##y,z,c), I[32] = (T)(img)(_n1##x,_n1##y,z,c), \
760  I[33] = (T)(img)(_n2##x,_n1##y,z,c), I[34] = (T)(img)(_n3##x,_n1##y,z,c), I[35] = (T)(img)(_p3##x,_n2##y,z,c), \
761  I[36] = (T)(img)(_p2##x,_n2##y,z,c), I[37] = (T)(img)(_p1##x,_n2##y,z,c), I[38] = (T)(img)(x,_n2##y,z,c), \
762  I[39] = (T)(img)(_n1##x,_n2##y,z,c), I[40] = (T)(img)(_n2##x,_n2##y,z,c), I[41] = (T)(img)(_n3##x,_n2##y,z,c), \
763  I[42] = (T)(img)(_p3##x,_n3##y,z,c), I[43] = (T)(img)(_p2##x,_n3##y,z,c), I[44] = (T)(img)(_p1##x,_n3##y,z,c), \
764  I[45] = (T)(img)(x,_n3##y,z,c), I[46] = (T)(img)(_n1##x,_n3##y,z,c), I[47] = (T)(img)(_n2##x,_n3##y,z,c), \
765  I[48] = (T)(img)(_n3##x,_n3##y,z,c)
766 
767 #define cimg_get8x8(img,x,y,z,c,I,T) \
768  I[0] = (T)(img)(_p3##x,_p3##y,z,c), I[1] = (T)(img)(_p2##x,_p3##y,z,c), I[2] = (T)(img)(_p1##x,_p3##y,z,c), \
769  I[3] = (T)(img)(x,_p3##y,z,c), I[4] = (T)(img)(_n1##x,_p3##y,z,c), I[5] = (T)(img)(_n2##x,_p3##y,z,c), \
770  I[6] = (T)(img)(_n3##x,_p3##y,z,c), I[7] = (T)(img)(_n4##x,_p3##y,z,c), I[8] = (T)(img)(_p3##x,_p2##y,z,c), \
771  I[9] = (T)(img)(_p2##x,_p2##y,z,c), I[10] = (T)(img)(_p1##x,_p2##y,z,c), I[11] = (T)(img)(x,_p2##y,z,c), \
772  I[12] = (T)(img)(_n1##x,_p2##y,z,c), I[13] = (T)(img)(_n2##x,_p2##y,z,c), I[14] = (T)(img)(_n3##x,_p2##y,z,c), \
773  I[15] = (T)(img)(_n4##x,_p2##y,z,c), I[16] = (T)(img)(_p3##x,_p1##y,z,c), I[17] = (T)(img)(_p2##x,_p1##y,z,c), \
774  I[18] = (T)(img)(_p1##x,_p1##y,z,c), I[19] = (T)(img)(x,_p1##y,z,c), I[20] = (T)(img)(_n1##x,_p1##y,z,c), \
775  I[21] = (T)(img)(_n2##x,_p1##y,z,c), I[22] = (T)(img)(_n3##x,_p1##y,z,c), I[23] = (T)(img)(_n4##x,_p1##y,z,c), \
776  I[24] = (T)(img)(_p3##x,y,z,c), I[25] = (T)(img)(_p2##x,y,z,c), I[26] = (T)(img)(_p1##x,y,z,c), \
777  I[27] = (T)(img)(x,y,z,c), I[28] = (T)(img)(_n1##x,y,z,c), I[29] = (T)(img)(_n2##x,y,z,c), \
778  I[30] = (T)(img)(_n3##x,y,z,c), I[31] = (T)(img)(_n4##x,y,z,c), I[32] = (T)(img)(_p3##x,_n1##y,z,c), \
779  I[33] = (T)(img)(_p2##x,_n1##y,z,c), I[34] = (T)(img)(_p1##x,_n1##y,z,c), I[35] = (T)(img)(x,_n1##y,z,c), \
780  I[36] = (T)(img)(_n1##x,_n1##y,z,c), I[37] = (T)(img)(_n2##x,_n1##y,z,c), I[38] = (T)(img)(_n3##x,_n1##y,z,c), \
781  I[39] = (T)(img)(_n4##x,_n1##y,z,c), I[40] = (T)(img)(_p3##x,_n2##y,z,c), I[41] = (T)(img)(_p2##x,_n2##y,z,c), \
782  I[42] = (T)(img)(_p1##x,_n2##y,z,c), I[43] = (T)(img)(x,_n2##y,z,c), I[44] = (T)(img)(_n1##x,_n2##y,z,c), \
783  I[45] = (T)(img)(_n2##x,_n2##y,z,c), I[46] = (T)(img)(_n3##x,_n2##y,z,c), I[47] = (T)(img)(_n4##x,_n2##y,z,c), \
784  I[48] = (T)(img)(_p3##x,_n3##y,z,c), I[49] = (T)(img)(_p2##x,_n3##y,z,c), I[50] = (T)(img)(_p1##x,_n3##y,z,c), \
785  I[51] = (T)(img)(x,_n3##y,z,c), I[52] = (T)(img)(_n1##x,_n3##y,z,c), I[53] = (T)(img)(_n2##x,_n3##y,z,c), \
786  I[54] = (T)(img)(_n3##x,_n3##y,z,c), I[55] = (T)(img)(_n4##x,_n3##y,z,c), I[56] = (T)(img)(_p3##x,_n4##y,z,c), \
787  I[57] = (T)(img)(_p2##x,_n4##y,z,c), I[58] = (T)(img)(_p1##x,_n4##y,z,c), I[59] = (T)(img)(x,_n4##y,z,c), \
788  I[60] = (T)(img)(_n1##x,_n4##y,z,c), I[61] = (T)(img)(_n2##x,_n4##y,z,c), I[62] = (T)(img)(_n3##x,_n4##y,z,c), \
789  I[63] = (T)(img)(_n4##x,_n4##y,z,c);
790 
791 #define cimg_get9x9(img,x,y,z,c,I,T) \
792  I[0] = (T)(img)(_p4##x,_p4##y,z,c), I[1] = (T)(img)(_p3##x,_p4##y,z,c), I[2] = (T)(img)(_p2##x,_p4##y,z,c), \
793  I[3] = (T)(img)(_p1##x,_p4##y,z,c), I[4] = (T)(img)(x,_p4##y,z,c), I[5] = (T)(img)(_n1##x,_p4##y,z,c), \
794  I[6] = (T)(img)(_n2##x,_p4##y,z,c), I[7] = (T)(img)(_n3##x,_p4##y,z,c), I[8] = (T)(img)(_n4##x,_p4##y,z,c), \
795  I[9] = (T)(img)(_p4##x,_p3##y,z,c), I[10] = (T)(img)(_p3##x,_p3##y,z,c), I[11] = (T)(img)(_p2##x,_p3##y,z,c), \
796  I[12] = (T)(img)(_p1##x,_p3##y,z,c), I[13] = (T)(img)(x,_p3##y,z,c), I[14] = (T)(img)(_n1##x,_p3##y,z,c), \
797  I[15] = (T)(img)(_n2##x,_p3##y,z,c), I[16] = (T)(img)(_n3##x,_p3##y,z,c), I[17] = (T)(img)(_n4##x,_p3##y,z,c), \
798  I[18] = (T)(img)(_p4##x,_p2##y,z,c), I[19] = (T)(img)(_p3##x,_p2##y,z,c), I[20] = (T)(img)(_p2##x,_p2##y,z,c), \
799  I[21] = (T)(img)(_p1##x,_p2##y,z,c), I[22] = (T)(img)(x,_p2##y,z,c), I[23] = (T)(img)(_n1##x,_p2##y,z,c), \
800  I[24] = (T)(img)(_n2##x,_p2##y,z,c), I[25] = (T)(img)(_n3##x,_p2##y,z,c), I[26] = (T)(img)(_n4##x,_p2##y,z,c), \
801  I[27] = (T)(img)(_p4##x,_p1##y,z,c), I[28] = (T)(img)(_p3##x,_p1##y,z,c), I[29] = (T)(img)(_p2##x,_p1##y,z,c), \
802  I[30] = (T)(img)(_p1##x,_p1##y,z,c), I[31] = (T)(img)(x,_p1##y,z,c), I[32] = (T)(img)(_n1##x,_p1##y,z,c), \
803  I[33] = (T)(img)(_n2##x,_p1##y,z,c), I[34] = (T)(img)(_n3##x,_p1##y,z,c), I[35] = (T)(img)(_n4##x,_p1##y,z,c), \
804  I[36] = (T)(img)(_p4##x,y,z,c), I[37] = (T)(img)(_p3##x,y,z,c), I[38] = (T)(img)(_p2##x,y,z,c), \
805  I[39] = (T)(img)(_p1##x,y,z,c), I[40] = (T)(img)(x,y,z,c), I[41] = (T)(img)(_n1##x,y,z,c), \
806  I[42] = (T)(img)(_n2##x,y,z,c), I[43] = (T)(img)(_n3##x,y,z,c), I[44] = (T)(img)(_n4##x,y,z,c), \
807  I[45] = (T)(img)(_p4##x,_n1##y,z,c), I[46] = (T)(img)(_p3##x,_n1##y,z,c), I[47] = (T)(img)(_p2##x,_n1##y,z,c), \
808  I[48] = (T)(img)(_p1##x,_n1##y,z,c), I[49] = (T)(img)(x,_n1##y,z,c), I[50] = (T)(img)(_n1##x,_n1##y,z,c), \
809  I[51] = (T)(img)(_n2##x,_n1##y,z,c), I[52] = (T)(img)(_n3##x,_n1##y,z,c), I[53] = (T)(img)(_n4##x,_n1##y,z,c), \
810  I[54] = (T)(img)(_p4##x,_n2##y,z,c), I[55] = (T)(img)(_p3##x,_n2##y,z,c), I[56] = (T)(img)(_p2##x,_n2##y,z,c), \
811  I[57] = (T)(img)(_p1##x,_n2##y,z,c), I[58] = (T)(img)(x,_n2##y,z,c), I[59] = (T)(img)(_n1##x,_n2##y,z,c), \
812  I[60] = (T)(img)(_n2##x,_n2##y,z,c), I[61] = (T)(img)(_n3##x,_n2##y,z,c), I[62] = (T)(img)(_n4##x,_n2##y,z,c), \
813  I[63] = (T)(img)(_p4##x,_n3##y,z,c), I[64] = (T)(img)(_p3##x,_n3##y,z,c), I[65] = (T)(img)(_p2##x,_n3##y,z,c), \
814  I[66] = (T)(img)(_p1##x,_n3##y,z,c), I[67] = (T)(img)(x,_n3##y,z,c), I[68] = (T)(img)(_n1##x,_n3##y,z,c), \
815  I[69] = (T)(img)(_n2##x,_n3##y,z,c), I[70] = (T)(img)(_n3##x,_n3##y,z,c), I[71] = (T)(img)(_n4##x,_n3##y,z,c), \
816  I[72] = (T)(img)(_p4##x,_n4##y,z,c), I[73] = (T)(img)(_p3##x,_n4##y,z,c), I[74] = (T)(img)(_p2##x,_n4##y,z,c), \
817  I[75] = (T)(img)(_p1##x,_n4##y,z,c), I[76] = (T)(img)(x,_n4##y,z,c), I[77] = (T)(img)(_n1##x,_n4##y,z,c), \
818  I[78] = (T)(img)(_n2##x,_n4##y,z,c), I[79] = (T)(img)(_n3##x,_n4##y,z,c), I[80] = (T)(img)(_n4##x,_n4##y,z,c)
819 
820 #define cimg_get2x2x2(img,x,y,z,c,I,T) \
821  I[0] = (T)(img)(x,y,z,c), I[1] = (T)(img)(_n1##x,y,z,c), I[2] = (T)(img)(x,_n1##y,z,c), \
822  I[3] = (T)(img)(_n1##x,_n1##y,z,c), I[4] = (T)(img)(x,y,_n1##z,c), I[5] = (T)(img)(_n1##x,y,_n1##z,c), \
823  I[6] = (T)(img)(x,_n1##y,_n1##z,c), I[7] = (T)(img)(_n1##x,_n1##y,_n1##z,c)
824 
825 #define cimg_get3x3x3(img,x,y,z,c,I,T) \
826  I[0] = (T)(img)(_p1##x,_p1##y,_p1##z,c), I[1] = (T)(img)(x,_p1##y,_p1##z,c), \
827  I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c), I[3] = (T)(img)(_p1##x,y,_p1##z,c), I[4] = (T)(img)(x,y,_p1##z,c), \
828  I[5] = (T)(img)(_n1##x,y,_p1##z,c), I[6] = (T)(img)(_p1##x,_n1##y,_p1##z,c), I[7] = (T)(img)(x,_n1##y,_p1##z,c), \
829  I[8] = (T)(img)(_n1##x,_n1##y,_p1##z,c), I[9] = (T)(img)(_p1##x,_p1##y,z,c), I[10] = (T)(img)(x,_p1##y,z,c), \
830  I[11] = (T)(img)(_n1##x,_p1##y,z,c), I[12] = (T)(img)(_p1##x,y,z,c), I[13] = (T)(img)(x,y,z,c), \
831  I[14] = (T)(img)(_n1##x,y,z,c), I[15] = (T)(img)(_p1##x,_n1##y,z,c), I[16] = (T)(img)(x,_n1##y,z,c), \
832  I[17] = (T)(img)(_n1##x,_n1##y,z,c), I[18] = (T)(img)(_p1##x,_p1##y,_n1##z,c), I[19] = (T)(img)(x,_p1##y,_n1##z,c), \
833  I[20] = (T)(img)(_n1##x,_p1##y,_n1##z,c), I[21] = (T)(img)(_p1##x,y,_n1##z,c), I[22] = (T)(img)(x,y,_n1##z,c), \
834  I[23] = (T)(img)(_n1##x,y,_n1##z,c), I[24] = (T)(img)(_p1##x,_n1##y,_n1##z,c), I[25] = (T)(img)(x,_n1##y,_n1##z,c), \
835  I[26] = (T)(img)(_n1##x,_n1##y,_n1##z,c)
836 
837 // Macros to perform various image loops.
838 //
839 // These macros are simpler to use than loops with C++ iterators.
840 #define cimg_for(img,ptrs,T_ptrs) \
841  for (T_ptrs *ptrs = (img)._data, *_max##ptrs = (img)._data + (img).size(); ptrs<_max##ptrs; ++ptrs)
842 #define cimg_rof(img,ptrs,T_ptrs) for (T_ptrs *ptrs = (img)._data + (img).size() - 1; ptrs>=(img)._data; --ptrs)
843 #define cimg_foroff(img,off) for (cimg_ulong off = 0, _max##off = (img).size(); off<_max##off; ++off)
844 
845 #define cimg_for1(bound,i) for (int i = 0; i<(int)(bound); ++i)
846 #define cimg_forX(img,x) cimg_for1((img)._width,x)
847 #define cimg_forY(img,y) cimg_for1((img)._height,y)
848 #define cimg_forZ(img,z) cimg_for1((img)._depth,z)
849 #define cimg_forC(img,c) cimg_for1((img)._spectrum,c)
850 #define cimg_forXY(img,x,y) cimg_forY(img,y) cimg_forX(img,x)
851 #define cimg_forXZ(img,x,z) cimg_forZ(img,z) cimg_forX(img,x)
852 #define cimg_forYZ(img,y,z) cimg_forZ(img,z) cimg_forY(img,y)
853 #define cimg_forXC(img,x,c) cimg_forC(img,c) cimg_forX(img,x)
854 #define cimg_forYC(img,y,c) cimg_forC(img,c) cimg_forY(img,y)
855 #define cimg_forZC(img,z,c) cimg_forC(img,c) cimg_forZ(img,z)
856 #define cimg_forXYZ(img,x,y,z) cimg_forZ(img,z) cimg_forXY(img,x,y)
857 #define cimg_forXYC(img,x,y,c) cimg_forC(img,c) cimg_forXY(img,x,y)
858 #define cimg_forXZC(img,x,z,c) cimg_forC(img,c) cimg_forXZ(img,x,z)
859 #define cimg_forYZC(img,y,z,c) cimg_forC(img,c) cimg_forYZ(img,y,z)
860 #define cimg_forXYZC(img,x,y,z,c) cimg_forC(img,c) cimg_forXYZ(img,x,y,z)
861 
862 #define cimg_rof1(bound,i) for (int i = (int)(bound) - 1; i>=0; --i)
863 #define cimg_rofX(img,x) cimg_rof1((img)._width,x)
864 #define cimg_rofY(img,y) cimg_rof1((img)._height,y)
865 #define cimg_rofZ(img,z) cimg_rof1((img)._depth,z)
866 #define cimg_rofC(img,c) cimg_rof1((img)._spectrum,c)
867 #define cimg_rofXY(img,x,y) cimg_rofY(img,y) cimg_rofX(img,x)
868 #define cimg_rofXZ(img,x,z) cimg_rofZ(img,z) cimg_rofX(img,x)
869 #define cimg_rofYZ(img,y,z) cimg_rofZ(img,z) cimg_rofY(img,y)
870 #define cimg_rofXC(img,x,c) cimg_rofC(img,c) cimg_rofX(img,x)
871 #define cimg_rofYC(img,y,c) cimg_rofC(img,c) cimg_rofY(img,y)
872 #define cimg_rofZC(img,z,c) cimg_rofC(img,c) cimg_rofZ(img,z)
873 #define cimg_rofXYZ(img,x,y,z) cimg_rofZ(img,z) cimg_rofXY(img,x,y)
874 #define cimg_rofXYC(img,x,y,c) cimg_rofC(img,c) cimg_rofXY(img,x,y)
875 #define cimg_rofXZC(img,x,z,c) cimg_rofC(img,c) cimg_rofXZ(img,x,z)
876 #define cimg_rofYZC(img,y,z,c) cimg_rofC(img,c) cimg_rofYZ(img,y,z)
877 #define cimg_rofXYZC(img,x,y,z,c) cimg_rofC(img,c) cimg_rofXYZ(img,x,y,z)
878 
879 #define cimg_for_in1(bound,i0,i1,i) \
880  for (int i = (int)(i0)<0?0:(int)(i0), _max##i = (int)(i1)<(int)(bound)?(int)(i1):(int)(bound) - 1; i<=_max##i; ++i)
881 #define cimg_for_inX(img,x0,x1,x) cimg_for_in1((img)._width,x0,x1,x)
882 #define cimg_for_inY(img,y0,y1,y) cimg_for_in1((img)._height,y0,y1,y)
883 #define cimg_for_inZ(img,z0,z1,z) cimg_for_in1((img)._depth,z0,z1,z)
884 #define cimg_for_inC(img,c0,c1,c) cimg_for_in1((img)._spectrum,c0,c1,c)
885 #define cimg_for_inXY(img,x0,y0,x1,y1,x,y) cimg_for_inY(img,y0,y1,y) cimg_for_inX(img,x0,x1,x)
886 #define cimg_for_inXZ(img,x0,z0,x1,z1,x,z) cimg_for_inZ(img,z0,z1,z) cimg_for_inX(img,x0,x1,x)
887 #define cimg_for_inXC(img,x0,c0,x1,c1,x,c) cimg_for_inC(img,c0,c1,c) cimg_for_inX(img,x0,x1,x)
888 #define cimg_for_inYZ(img,y0,z0,y1,z1,y,z) cimg_for_inZ(img,x0,z1,z) cimg_for_inY(img,y0,y1,y)
889 #define cimg_for_inYC(img,y0,c0,y1,c1,y,c) cimg_for_inC(img,c0,c1,c) cimg_for_inY(img,y0,y1,y)
890 #define cimg_for_inZC(img,z0,c0,z1,c1,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inZ(img,z0,z1,z)
891 #define cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_inZ(img,z0,z1,z) cimg_for_inXY(img,x0,y0,x1,y1,x,y)
892 #define cimg_for_inXYC(img,x0,y0,c0,x1,y1,c1,x,y,c) cimg_for_inC(img,c0,c1,c) cimg_for_inXY(img,x0,y0,x1,y1,x,y)
893 #define cimg_for_inXZC(img,x0,z0,c0,x1,z1,c1,x,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inXZ(img,x0,z0,x1,z1,x,z)
894 #define cimg_for_inYZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inYZ(img,y0,z0,y1,z1,y,z)
895 #define cimg_for_inXYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \
896  cimg_for_inC(img,c0,c1,c) cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
897 #define cimg_for_insideX(img,x,n) cimg_for_inX(img,n,(img)._width - 1 - (n),x)
898 #define cimg_for_insideY(img,y,n) cimg_for_inY(img,n,(img)._height - 1 - (n),y)
899 #define cimg_for_insideZ(img,z,n) cimg_for_inZ(img,n,(img)._depth - 1 - (n),z)
900 #define cimg_for_insideC(img,c,n) cimg_for_inC(img,n,(img)._spectrum - 1 - (n),c)
901 #define cimg_for_insideXY(img,x,y,n) cimg_for_inXY(img,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),x,y)
902 #define cimg_for_insideXYZ(img,x,y,z,n) \
903  cimg_for_inXYZ(img,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),(img)._depth - 1 - (n),x,y,z)
904 #define cimg_for_insideXYZC(img,x,y,z,c,n) \
905  cimg_for_inXYZ(img,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),(img)._depth - 1 - (n),x,y,z)
906 
907 #define cimg_for_out1(boundi,i0,i1,i) \
908  for (int i = (int)(i0)>0?0:(int)(i1) + 1; i<(int)(boundi); ++i, i = i==(int)(i0)?(int)(i1) + 1:i)
909 #define cimg_for_out2(boundi,boundj,i0,j0,i1,j1,i,j) \
910  for (int j = 0; j<(int)(boundj); ++j) \
911  for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j?0:(int)(i0)>0?0:(int)(i1) + 1; i<(int)(boundi); \
912  ++i, i = _n1j?i:(i==(int)(i0)?(int)(i1) + 1:i))
913 #define cimg_for_out3(boundi,boundj,boundk,i0,j0,k0,i1,j1,k1,i,j,k) \
914  for (int k = 0; k<(int)(boundk); ++k) \
915  for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \
916  for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k?0:(int)(i0)>0?0:(int)(i1) + 1; i<(int)(boundi); \
917  ++i, i = _n1j || _n1k?i:(i==(int)(i0)?(int)(i1) + 1:i))
918 #define cimg_for_out4(boundi,boundj,boundk,boundl,i0,j0,k0,l0,i1,j1,k1,l1,i,j,k,l) \
919  for (int l = 0; l<(int)(boundl); ++l) \
920  for (int _n1l = (int)(l<(int)(l0) || l>(int)(l1)), k = 0; k<(int)(boundk); ++k) \
921  for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \
922  for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k || _n1l?0:(int)(i0)>0?0:(int)(i1) + 1; \
923  i<(int)(boundi); ++i, i = _n1j || _n1k || _n1l?i:(i==(int)(i0)?(int)(i1) + 1:i))
924 #define cimg_for_outX(img,x0,x1,x) cimg_for_out1((img)._width,x0,x1,x)
925 #define cimg_for_outY(img,y0,y1,y) cimg_for_out1((img)._height,y0,y1,y)
926 #define cimg_for_outZ(img,z0,z1,z) cimg_for_out1((img)._depth,z0,z1,z)
927 #define cimg_for_outC(img,c0,c1,c) cimg_for_out1((img)._spectrum,c0,c1,c)
928 #define cimg_for_outXY(img,x0,y0,x1,y1,x,y) cimg_for_out2((img)._width,(img)._height,x0,y0,x1,y1,x,y)
929 #define cimg_for_outXZ(img,x0,z0,x1,z1,x,z) cimg_for_out2((img)._width,(img)._depth,x0,z0,x1,z1,x,z)
930 #define cimg_for_outXC(img,x0,c0,x1,c1,x,c) cimg_for_out2((img)._width,(img)._spectrum,x0,c0,x1,c1,x,c)
931 #define cimg_for_outYZ(img,y0,z0,y1,z1,y,z) cimg_for_out2((img)._height,(img)._depth,y0,z0,y1,z1,y,z)
932 #define cimg_for_outYC(img,y0,c0,y1,c1,y,c) cimg_for_out2((img)._height,(img)._spectrum,y0,c0,y1,c1,y,c)
933 #define cimg_for_outZC(img,z0,c0,z1,c1,z,c) cimg_for_out2((img)._depth,(img)._spectrum,z0,c0,z1,c1,z,c)
934 #define cimg_for_outXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) \
935  cimg_for_out3((img)._width,(img)._height,(img)._depth,x0,y0,z0,x1,y1,z1,x,y,z)
936 #define cimg_for_outXYC(img,x0,y0,c0,x1,y1,c1,x,y,c) \
937  cimg_for_out3((img)._width,(img)._height,(img)._spectrum,x0,y0,c0,x1,y1,c1,x,y,c)
938 #define cimg_for_outXZC(img,x0,z0,c0,x1,z1,c1,x,z,c) \
939  cimg_for_out3((img)._width,(img)._depth,(img)._spectrum,x0,z0,c0,x1,z1,c1,x,z,c)
940 #define cimg_for_outYZC(img,y0,z0,c0,y1,z1,c1,y,z,c) \
941  cimg_for_out3((img)._height,(img)._depth,(img)._spectrum,y0,z0,c0,y1,z1,c1,y,z,c)
942 #define cimg_for_outXYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \
943  cimg_for_out4((img)._width,(img)._height,(img)._depth,(img)._spectrum,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c)
944 #define cimg_for_borderX(img,x,n) cimg_for_outX(img,n,(img)._width - 1 - (n),x)
945 #define cimg_for_borderY(img,y,n) cimg_for_outY(img,n,(img)._height - 1 - (n),y)
946 #define cimg_for_borderZ(img,z,n) cimg_for_outZ(img,n,(img)._depth - 1 - (n),z)
947 #define cimg_for_borderC(img,c,n) cimg_for_outC(img,n,(img)._spectrum - 1 - (n),c)
948 #define cimg_for_borderXY(img,x,y,n) cimg_for_outXY(img,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),x,y)
949 #define cimg_for_borderXYZ(img,x,y,z,n) \
950  cimg_for_outXYZ(img,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),(img)._depth - 1 - (n),x,y,z)
951 #define cimg_for_borderXYZC(img,x,y,z,c,n) \
952  cimg_for_outXYZC(img,n,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n), \
953  (img)._depth - 1 - (n),(img)._spectrum - 1 - (n),x,y,z,c)
954 
955 #define cimg_for_spiralXY(img,x,y) \
956  for (int x = 0, y = 0, _n1##x = 1, _n1##y = (img).width()*(img).height(); _n1##y; \
957  --_n1##y, _n1##x+=(_n1##x>>2) - ((!(_n1##x&3)?--y:((_n1##x&3)==1?(img)._width - 1 - ++x:\
958  ((_n1##x&3)==2?(img)._height - 1 - ++y:--x))))?0:1)
959 
960 #define cimg_for_lineXY(x,y,x0,y0,x1,y1) \
961  for (int x = (int)(x0), y = (int)(y0), _sx = 1, _sy = 1, _steep = 0, \
962  _dx=(x1)>(x0)?(int)(x1) - (int)(x0):(_sx=-1,(int)(x0) - (int)(x1)), \
963  _dy=(y1)>(y0)?(int)(y1) - (int)(y0):(_sy=-1,(int)(y0) - (int)(y1)), \
964  _counter = _dx, \
965  _err = _dx>_dy?(_dy>>1):((_steep=1),(_counter=_dy),(_dx>>1)); \
966  _counter>=0; \
967  --_counter, x+=_steep? \
968  (y+=_sy,(_err-=_dx)<0?_err+=_dy,_sx:0): \
969  (y+=(_err-=_dy)<0?_err+=_dx,_sy:0,_sx))
970 
971 #define cimg_for2(bound,i) \
972  for (int i = 0, _n1##i = 1>=(bound)?(int)(bound) - 1:1; \
973  _n1##i<(int)(bound) || i==--_n1##i; \
974  ++i, ++_n1##i)
975 #define cimg_for2X(img,x) cimg_for2((img)._width,x)
976 #define cimg_for2Y(img,y) cimg_for2((img)._height,y)
977 #define cimg_for2Z(img,z) cimg_for2((img)._depth,z)
978 #define cimg_for2C(img,c) cimg_for2((img)._spectrum,c)
979 #define cimg_for2XY(img,x,y) cimg_for2Y(img,y) cimg_for2X(img,x)
980 #define cimg_for2XZ(img,x,z) cimg_for2Z(img,z) cimg_for2X(img,x)
981 #define cimg_for2XC(img,x,c) cimg_for2C(img,c) cimg_for2X(img,x)
982 #define cimg_for2YZ(img,y,z) cimg_for2Z(img,z) cimg_for2Y(img,y)
983 #define cimg_for2YC(img,y,c) cimg_for2C(img,c) cimg_for2Y(img,y)
984 #define cimg_for2ZC(img,z,c) cimg_for2C(img,c) cimg_for2Z(img,z)
985 #define cimg_for2XYZ(img,x,y,z) cimg_for2Z(img,z) cimg_for2XY(img,x,y)
986 #define cimg_for2XZC(img,x,z,c) cimg_for2C(img,c) cimg_for2XZ(img,x,z)
987 #define cimg_for2YZC(img,y,z,c) cimg_for2C(img,c) cimg_for2YZ(img,y,z)
988 #define cimg_for2XYZC(img,x,y,z,c) cimg_for2C(img,c) cimg_for2XYZ(img,x,y,z)
989 
990 #define cimg_for_in2(bound,i0,i1,i) \
991  for (int i = (int)(i0)<0?0:(int)(i0), \
992  _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1; \
993  i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \
994  ++i, ++_n1##i)
995 #define cimg_for_in2X(img,x0,x1,x) cimg_for_in2((img)._width,x0,x1,x)
996 #define cimg_for_in2Y(img,y0,y1,y) cimg_for_in2((img)._height,y0,y1,y)
997 #define cimg_for_in2Z(img,z0,z1,z) cimg_for_in2((img)._depth,z0,z1,z)
998 #define cimg_for_in2C(img,c0,c1,c) cimg_for_in2((img)._spectrum,c0,c1,c)
999 #define cimg_for_in2XY(img,x0,y0,x1,y1,x,y) cimg_for_in2Y(img,y0,y1,y) cimg_for_in2X(img,x0,x1,x)
1000 #define cimg_for_in2XZ(img,x0,z0,x1,z1,x,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2X(img,x0,x1,x)
1001 #define cimg_for_in2XC(img,x0,c0,x1,c1,x,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2X(img,x0,x1,x)
1002 #define cimg_for_in2YZ(img,y0,z0,y1,z1,y,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2Y(img,y0,y1,y)
1003 #define cimg_for_in2YC(img,y0,c0,y1,c1,y,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2Y(img,y0,y1,y)
1004 #define cimg_for_in2ZC(img,z0,c0,z1,c1,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2Z(img,z0,z1,z)
1005 #define cimg_for_in2XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2XY(img,x0,y0,x1,y1,x,y)
1006 #define cimg_for_in2XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2XZ(img,x0,y0,x1,y1,x,z)
1007 #define cimg_for_in2YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2YZ(img,y0,z0,y1,z1,y,z)
1008 #define cimg_for_in2XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \
1009  cimg_for_in2C(img,c0,c1,c) cimg_for_in2XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
1010 
1011 #define cimg_for3(bound,i) \
1012  for (int i = 0, _p1##i = 0, \
1013  _n1##i = 1>=(bound)?(int)(bound) - 1:1; \
1014  _n1##i<(int)(bound) || i==--_n1##i; \
1015  _p1##i = i++, ++_n1##i)
1016 #define cimg_for3X(img,x) cimg_for3((img)._width,x)
1017 #define cimg_for3Y(img,y) cimg_for3((img)._height,y)
1018 #define cimg_for3Z(img,z) cimg_for3((img)._depth,z)
1019 #define cimg_for3C(img,c) cimg_for3((img)._spectrum,c)
1020 #define cimg_for3XY(img,x,y) cimg_for3Y(img,y) cimg_for3X(img,x)
1021 #define cimg_for3XZ(img,x,z) cimg_for3Z(img,z) cimg_for3X(img,x)
1022 #define cimg_for3XC(img,x,c) cimg_for3C(img,c) cimg_for3X(img,x)
1023 #define cimg_for3YZ(img,y,z) cimg_for3Z(img,z) cimg_for3Y(img,y)
1024 #define cimg_for3YC(img,y,c) cimg_for3C(img,c) cimg_for3Y(img,y)
1025 #define cimg_for3ZC(img,z,c) cimg_for3C(img,c) cimg_for3Z(img,z)
1026 #define cimg_for3XYZ(img,x,y,z) cimg_for3Z(img,z) cimg_for3XY(img,x,y)
1027 #define cimg_for3XZC(img,x,z,c) cimg_for3C(img,c) cimg_for3XZ(img,x,z)
1028 #define cimg_for3YZC(img,y,z,c) cimg_for3C(img,c) cimg_for3YZ(img,y,z)
1029 #define cimg_for3XYZC(img,x,y,z,c) cimg_for3C(img,c) cimg_for3XYZ(img,x,y,z)
1030 
1031 #define cimg_for_in3(bound,i0,i1,i) \
1032  for (int i = (int)(i0)<0?0:(int)(i0), \
1033  _p1##i = i - 1<0?0:i - 1, \
1034  _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1; \
1035  i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \
1036  _p1##i = i++, ++_n1##i)
1037 #define cimg_for_in3X(img,x0,x1,x) cimg_for_in3((img)._width,x0,x1,x)
1038 #define cimg_for_in3Y(img,y0,y1,y) cimg_for_in3((img)._height,y0,y1,y)
1039 #define cimg_for_in3Z(img,z0,z1,z) cimg_for_in3((img)._depth,z0,z1,z)
1040 #define cimg_for_in3C(img,c0,c1,c) cimg_for_in3((img)._spectrum,c0,c1,c)
1041 #define cimg_for_in3XY(img,x0,y0,x1,y1,x,y) cimg_for_in3Y(img,y0,y1,y) cimg_for_in3X(img,x0,x1,x)
1042 #define cimg_for_in3XZ(img,x0,z0,x1,z1,x,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3X(img,x0,x1,x)
1043 #define cimg_for_in3XC(img,x0,c0,x1,c1,x,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3X(img,x0,x1,x)
1044 #define cimg_for_in3YZ(img,y0,z0,y1,z1,y,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3Y(img,y0,y1,y)
1045 #define cimg_for_in3YC(img,y0,c0,y1,c1,y,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3Y(img,y0,y1,y)
1046 #define cimg_for_in3ZC(img,z0,c0,z1,c1,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3Z(img,z0,z1,z)
1047 #define cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3XY(img,x0,y0,x1,y1,x,y)
1048 #define cimg_for_in3XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3XZ(img,x0,y0,x1,y1,x,z)
1049 #define cimg_for_in3YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3YZ(img,y0,z0,y1,z1,y,z)
1050 #define cimg_for_in3XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \
1051  cimg_for_in3C(img,c0,c1,c) cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
1052 
1053 #define cimg_for4(bound,i) \
1054  for (int i = 0, _p1##i = 0, _n1##i = 1>=(bound)?(int)(bound) - 1:1, \
1055  _n2##i = 2>=(bound)?(int)(bound) - 1:2; \
1056  _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \
1057  _p1##i = i++, ++_n1##i, ++_n2##i)
1058 #define cimg_for4X(img,x) cimg_for4((img)._width,x)
1059 #define cimg_for4Y(img,y) cimg_for4((img)._height,y)
1060 #define cimg_for4Z(img,z) cimg_for4((img)._depth,z)
1061 #define cimg_for4C(img,c) cimg_for4((img)._spectrum,c)
1062 #define cimg_for4XY(img,x,y) cimg_for4Y(img,y) cimg_for4X(img,x)
1063 #define cimg_for4XZ(img,x,z) cimg_for4Z(img,z) cimg_for4X(img,x)
1064 #define cimg_for4XC(img,x,c) cimg_for4C(img,c) cimg_for4X(img,x)
1065 #define cimg_for4YZ(img,y,z) cimg_for4Z(img,z) cimg_for4Y(img,y)
1066 #define cimg_for4YC(img,y,c) cimg_for4C(img,c) cimg_for4Y(img,y)
1067 #define cimg_for4ZC(img,z,c) cimg_for4C(img,c) cimg_for4Z(img,z)
1068 #define cimg_for4XYZ(img,x,y,z) cimg_for4Z(img,z) cimg_for4XY(img,x,y)
1069 #define cimg_for4XZC(img,x,z,c) cimg_for4C(img,c) cimg_for4XZ(img,x,z)
1070 #define cimg_for4YZC(img,y,z,c) cimg_for4C(img,c) cimg_for4YZ(img,y,z)
1071 #define cimg_for4XYZC(img,x,y,z,c) cimg_for4C(img,c) cimg_for4XYZ(img,x,y,z)
1072 
1073 #define cimg_for_in4(bound,i0,i1,i) \
1074  for (int i = (int)(i0)<0?0:(int)(i0), \
1075  _p1##i = i - 1<0?0:i - 1, \
1076  _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \
1077  _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2; \
1078  i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \
1079  _p1##i = i++, ++_n1##i, ++_n2##i)
1080 #define cimg_for_in4X(img,x0,x1,x) cimg_for_in4((img)._width,x0,x1,x)
1081 #define cimg_for_in4Y(img,y0,y1,y) cimg_for_in4((img)._height,y0,y1,y)
1082 #define cimg_for_in4Z(img,z0,z1,z) cimg_for_in4((img)._depth,z0,z1,z)
1083 #define cimg_for_in4C(img,c0,c1,c) cimg_for_in4((img)._spectrum,c0,c1,c)
1084 #define cimg_for_in4XY(img,x0,y0,x1,y1,x,y) cimg_for_in4Y(img,y0,y1,y) cimg_for_in4X(img,x0,x1,x)
1085 #define cimg_for_in4XZ(img,x0,z0,x1,z1,x,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4X(img,x0,x1,x)
1086 #define cimg_for_in4XC(img,x0,c0,x1,c1,x,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4X(img,x0,x1,x)
1087 #define cimg_for_in4YZ(img,y0,z0,y1,z1,y,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4Y(img,y0,y1,y)
1088 #define cimg_for_in4YC(img,y0,c0,y1,c1,y,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4Y(img,y0,y1,y)
1089 #define cimg_for_in4ZC(img,z0,c0,z1,c1,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4Z(img,z0,z1,z)
1090 #define cimg_for_in4XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4XY(img,x0,y0,x1,y1,x,y)
1091 #define cimg_for_in4XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4XZ(img,x0,y0,x1,y1,x,z)
1092 #define cimg_for_in4YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4YZ(img,y0,z0,y1,z1,y,z)
1093 #define cimg_for_in4XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \
1094  cimg_for_in4C(img,c0,c1,c) cimg_for_in4XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
1095 
1096 #define cimg_for5(bound,i) \
1097  for (int i = 0, _p2##i = 0, _p1##i = 0, \
1098  _n1##i = 1>=(bound)?(int)(bound) - 1:1, \
1099  _n2##i = 2>=(bound)?(int)(bound) - 1:2; \
1100  _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \
1101  _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)
1102 #define cimg_for5X(img,x) cimg_for5((img)._width,x)
1103 #define cimg_for5Y(img,y) cimg_for5((img)._height,y)
1104 #define cimg_for5Z(img,z) cimg_for5((img)._depth,z)
1105 #define cimg_for5C(img,c) cimg_for5((img)._spectrum,c)
1106 #define cimg_for5XY(img,x,y) cimg_for5Y(img,y) cimg_for5X(img,x)
1107 #define cimg_for5XZ(img,x,z) cimg_for5Z(img,z) cimg_for5X(img,x)
1108 #define cimg_for5XC(img,x,c) cimg_for5C(img,c) cimg_for5X(img,x)
1109 #define cimg_for5YZ(img,y,z) cimg_for5Z(img,z) cimg_for5Y(img,y)
1110 #define cimg_for5YC(img,y,c) cimg_for5C(img,c) cimg_for5Y(img,y)
1111 #define cimg_for5ZC(img,z,c) cimg_for5C(img,c) cimg_for5Z(img,z)
1112 #define cimg_for5XYZ(img,x,y,z) cimg_for5Z(img,z) cimg_for5XY(img,x,y)
1113 #define cimg_for5XZC(img,x,z,c) cimg_for5C(img,c) cimg_for5XZ(img,x,z)
1114 #define cimg_for5YZC(img,y,z,c) cimg_for5C(img,c) cimg_for5YZ(img,y,z)
1115 #define cimg_for5XYZC(img,x,y,z,c) cimg_for5C(img,c) cimg_for5XYZ(img,x,y,z)
1116 
1117 #define cimg_for_in5(bound,i0,i1,i) \
1118  for (int i = (int)(i0)<0?0:(int)(i0), \
1119  _p2##i = i - 2<0?0:i - 2, \
1120  _p1##i = i - 1<0?0:i - 1, \
1121  _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \
1122  _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2; \
1123  i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \
1124  _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)
1125 #define cimg_for_in5X(img,x0,x1,x) cimg_for_in5((img)._width,x0,x1,x)
1126 #define cimg_for_in5Y(img,y0,y1,y) cimg_for_in5((img)._height,y0,y1,y)
1127 #define cimg_for_in5Z(img,z0,z1,z) cimg_for_in5((img)._depth,z0,z1,z)
1128 #define cimg_for_in5C(img,c0,c1,c) cimg_for_in5((img)._spectrum,c0,c1,c)
1129 #define cimg_for_in5XY(img,x0,y0,x1,y1,x,y) cimg_for_in5Y(img,y0,y1,y) cimg_for_in5X(img,x0,x1,x)
1130 #define cimg_for_in5XZ(img,x0,z0,x1,z1,x,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5X(img,x0,x1,x)
1131 #define cimg_for_in5XC(img,x0,c0,x1,c1,x,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5X(img,x0,x1,x)
1132 #define cimg_for_in5YZ(img,y0,z0,y1,z1,y,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5Y(img,y0,y1,y)
1133 #define cimg_for_in5YC(img,y0,c0,y1,c1,y,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5Y(img,y0,y1,y)
1134 #define cimg_for_in5ZC(img,z0,c0,z1,c1,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5Z(img,z0,z1,z)
1135 #define cimg_for_in5XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5XY(img,x0,y0,x1,y1,x,y)
1136 #define cimg_for_in5XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5XZ(img,x0,y0,x1,y1,x,z)
1137 #define cimg_for_in5YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5YZ(img,y0,z0,y1,z1,y,z)
1138 #define cimg_for_in5XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \
1139  cimg_for_in5C(img,c0,c1,c) cimg_for_in5XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
1140 
1141 #define cimg_for6(bound,i) \
1142  for (int i = 0, _p2##i = 0, _p1##i = 0, \
1143  _n1##i = 1>=(bound)?(int)(bound) - 1:1, \
1144  _n2##i = 2>=(bound)?(int)(bound) - 1:2, \
1145  _n3##i = 3>=(bound)?(int)(bound) - 1:3; \
1146  _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \
1147  _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
1148 #define cimg_for6X(img,x) cimg_for6((img)._width,x)
1149 #define cimg_for6Y(img,y) cimg_for6((img)._height,y)
1150 #define cimg_for6Z(img,z) cimg_for6((img)._depth,z)
1151 #define cimg_for6C(img,c) cimg_for6((img)._spectrum,c)
1152 #define cimg_for6XY(img,x,y) cimg_for6Y(img,y) cimg_for6X(img,x)
1153 #define cimg_for6XZ(img,x,z) cimg_for6Z(img,z) cimg_for6X(img,x)
1154 #define cimg_for6XC(img,x,c) cimg_for6C(img,c) cimg_for6X(img,x)
1155 #define cimg_for6YZ(img,y,z) cimg_for6Z(img,z) cimg_for6Y(img,y)
1156 #define cimg_for6YC(img,y,c) cimg_for6C(img,c) cimg_for6Y(img,y)
1157 #define cimg_for6ZC(img,z,c) cimg_for6C(img,c) cimg_for6Z(img,z)
1158 #define cimg_for6XYZ(img,x,y,z) cimg_for6Z(img,z) cimg_for6XY(img,x,y)
1159 #define cimg_for6XZC(img,x,z,c) cimg_for6C(img,c) cimg_for6XZ(img,x,z)
1160 #define cimg_for6YZC(img,y,z,c) cimg_for6C(img,c) cimg_for6YZ(img,y,z)
1161 #define cimg_for6XYZC(img,x,y,z,c) cimg_for6C(img,c) cimg_for6XYZ(img,x,y,z)
1162 
1163 #define cimg_for_in6(bound,i0,i1,i) \
1164  for (int i = (int)(i0)<0?0:(int)(i0), \
1165  _p2##i = i - 2<0?0:i - 2, \
1166  _p1##i = i - 1<0?0:i - 1, \
1167  _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \
1168  _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \
1169  _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3; \
1170  i<=(int)(i1) && \
1171  (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \
1172  _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
1173 #define cimg_for_in6X(img,x0,x1,x) cimg_for_in6((img)._width,x0,x1,x)
1174 #define cimg_for_in6Y(img,y0,y1,y) cimg_for_in6((img)._height,y0,y1,y)
1175 #define cimg_for_in6Z(img,z0,z1,z) cimg_for_in6((img)._depth,z0,z1,z)
1176 #define cimg_for_in6C(img,c0,c1,c) cimg_for_in6((img)._spectrum,c0,c1,c)
1177 #define cimg_for_in6XY(img,x0,y0,x1,y1,x,y) cimg_for_in6Y(img,y0,y1,y) cimg_for_in6X(img,x0,x1,x)
1178 #define cimg_for_in6XZ(img,x0,z0,x1,z1,x,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6X(img,x0,x1,x)
1179 #define cimg_for_in6XC(img,x0,c0,x1,c1,x,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6X(img,x0,x1,x)
1180 #define cimg_for_in6YZ(img,y0,z0,y1,z1,y,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6Y(img,y0,y1,y)
1181 #define cimg_for_in6YC(img,y0,c0,y1,c1,y,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6Y(img,y0,y1,y)
1182 #define cimg_for_in6ZC(img,z0,c0,z1,c1,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6Z(img,z0,z1,z)
1183 #define cimg_for_in6XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6XY(img,x0,y0,x1,y1,x,y)
1184 #define cimg_for_in6XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6XZ(img,x0,y0,x1,y1,x,z)
1185 #define cimg_for_in6YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6YZ(img,y0,z0,y1,z1,y,z)
1186 #define cimg_for_in6XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \
1187  cimg_for_in6C(img,c0,c1,c) cimg_for_in6XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
1188 
1189 #define cimg_for7(bound,i) \
1190  for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
1191  _n1##i = 1>=(bound)?(int)(bound) - 1:1, \
1192  _n2##i = 2>=(bound)?(int)(bound) - 1:2, \
1193  _n3##i = 3>=(bound)?(int)(bound) - 1:3; \
1194  _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \
1195  _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
1196 #define cimg_for7X(img,x) cimg_for7((img)._width,x)
1197 #define cimg_for7Y(img,y) cimg_for7((img)._height,y)
1198 #define cimg_for7Z(img,z) cimg_for7((img)._depth,z)
1199 #define cimg_for7C(img,c) cimg_for7((img)._spectrum,c)
1200 #define cimg_for7XY(img,x,y) cimg_for7Y(img,y) cimg_for7X(img,x)
1201 #define cimg_for7XZ(img,x,z) cimg_for7Z(img,z) cimg_for7X(img,x)
1202 #define cimg_for7XC(img,x,c) cimg_for7C(img,c) cimg_for7X(img,x)
1203 #define cimg_for7YZ(img,y,z) cimg_for7Z(img,z) cimg_for7Y(img,y)
1204 #define cimg_for7YC(img,y,c) cimg_for7C(img,c) cimg_for7Y(img,y)
1205 #define cimg_for7ZC(img,z,c) cimg_for7C(img,c) cimg_for7Z(img,z)
1206 #define cimg_for7XYZ(img,x,y,z) cimg_for7Z(img,z) cimg_for7XY(img,x,y)
1207 #define cimg_for7XZC(img,x,z,c) cimg_for7C(img,c) cimg_for7XZ(img,x,z)
1208 #define cimg_for7YZC(img,y,z,c) cimg_for7C(img,c) cimg_for7YZ(img,y,z)
1209 #define cimg_for7XYZC(img,x,y,z,c) cimg_for7C(img,c) cimg_for7XYZ(img,x,y,z)
1210 
1211 #define cimg_for_in7(bound,i0,i1,i) \
1212  for (int i = (int)(i0)<0?0:(int)(i0), \
1213  _p3##i = i - 3<0?0:i - 3, \
1214  _p2##i = i - 2<0?0:i - 2, \
1215  _p1##i = i - 1<0?0:i - 1, \
1216  _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \
1217  _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \
1218  _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3; \
1219  i<=(int)(i1) && \
1220  (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \
1221  _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
1222 #define cimg_for_in7X(img,x0,x1,x) cimg_for_in7((img)._width,x0,x1,x)
1223 #define cimg_for_in7Y(img,y0,y1,y) cimg_for_in7((img)._height,y0,y1,y)
1224 #define cimg_for_in7Z(img,z0,z1,z) cimg_for_in7((img)._depth,z0,z1,z)
1225 #define cimg_for_in7C(img,c0,c1,c) cimg_for_in7((img)._spectrum,c0,c1,c)
1226 #define cimg_for_in7XY(img,x0,y0,x1,y1,x,y) cimg_for_in7Y(img,y0,y1,y) cimg_for_in7X(img,x0,x1,x)
1227 #define cimg_for_in7XZ(img,x0,z0,x1,z1,x,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7X(img,x0,x1,x)
1228 #define cimg_for_in7XC(img,x0,c0,x1,c1,x,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7X(img,x0,x1,x)
1229 #define cimg_for_in7YZ(img,y0,z0,y1,z1,y,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7Y(img,y0,y1,y)
1230 #define cimg_for_in7YC(img,y0,c0,y1,c1,y,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7Y(img,y0,y1,y)
1231 #define cimg_for_in7ZC(img,z0,c0,z1,c1,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7Z(img,z0,z1,z)
1232 #define cimg_for_in7XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7XY(img,x0,y0,x1,y1,x,y)
1233 #define cimg_for_in7XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7XZ(img,x0,y0,x1,y1,x,z)
1234 #define cimg_for_in7YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7YZ(img,y0,z0,y1,z1,y,z)
1235 #define cimg_for_in7XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \
1236  cimg_for_in7C(img,c0,c1,c) cimg_for_in7XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
1237 
1238 #define cimg_for8(bound,i) \
1239  for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
1240  _n1##i = 1>=(bound)?(int)(bound) - 1:1, \
1241  _n2##i = 2>=(bound)?(int)(bound) - 1:2, \
1242  _n3##i = 3>=(bound)?(int)(bound) - 1:3, \
1243  _n4##i = 4>=(bound)?(int)(bound) - 1:4; \
1244  _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
1245  i==(_n4##i = _n3##i = _n2##i = --_n1##i); \
1246  _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
1247 #define cimg_for8X(img,x) cimg_for8((img)._width,x)
1248 #define cimg_for8Y(img,y) cimg_for8((img)._height,y)
1249 #define cimg_for8Z(img,z) cimg_for8((img)._depth,z)
1250 #define cimg_for8C(img,c) cimg_for8((img)._spectrum,c)
1251 #define cimg_for8XY(img,x,y) cimg_for8Y(img,y) cimg_for8X(img,x)
1252 #define cimg_for8XZ(img,x,z) cimg_for8Z(img,z) cimg_for8X(img,x)
1253 #define cimg_for8XC(img,x,c) cimg_for8C(img,c) cimg_for8X(img,x)
1254 #define cimg_for8YZ(img,y,z) cimg_for8Z(img,z) cimg_for8Y(img,y)
1255 #define cimg_for8YC(img,y,c) cimg_for8C(img,c) cimg_for8Y(img,y)
1256 #define cimg_for8ZC(img,z,c) cimg_for8C(img,c) cimg_for8Z(img,z)
1257 #define cimg_for8XYZ(img,x,y,z) cimg_for8Z(img,z) cimg_for8XY(img,x,y)
1258 #define cimg_for8XZC(img,x,z,c) cimg_for8C(img,c) cimg_for8XZ(img,x,z)
1259 #define cimg_for8YZC(img,y,z,c) cimg_for8C(img,c) cimg_for8YZ(img,y,z)
1260 #define cimg_for8XYZC(img,x,y,z,c) cimg_for8C(img,c) cimg_for8XYZ(img,x,y,z)
1261 
1262 #define cimg_for_in8(bound,i0,i1,i) \
1263  for (int i = (int)(i0)<0?0:(int)(i0), \
1264  _p3##i = i - 3<0?0:i - 3, \
1265  _p2##i = i - 2<0?0:i - 2, \
1266  _p1##i = i - 1<0?0:i - 1, \
1267  _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \
1268  _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \
1269  _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3, \
1270  _n4##i = i + 4>=(int)(bound)?(int)(bound) - 1:i + 4; \
1271  i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
1272  i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \
1273  _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
1274 #define cimg_for_in8X(img,x0,x1,x) cimg_for_in8((img)._width,x0,x1,x)
1275 #define cimg_for_in8Y(img,y0,y1,y) cimg_for_in8((img)._height,y0,y1,y)
1276 #define cimg_for_in8Z(img,z0,z1,z) cimg_for_in8((img)._depth,z0,z1,z)
1277 #define cimg_for_in8C(img,c0,c1,c) cimg_for_in8((img)._spectrum,c0,c1,c)
1278 #define cimg_for_in8XY(img,x0,y0,x1,y1,x,y) cimg_for_in8Y(img,y0,y1,y) cimg_for_in8X(img,x0,x1,x)
1279 #define cimg_for_in8XZ(img,x0,z0,x1,z1,x,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8X(img,x0,x1,x)
1280 #define cimg_for_in8XC(img,x0,c0,x1,c1,x,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8X(img,x0,x1,x)
1281 #define cimg_for_in8YZ(img,y0,z0,y1,z1,y,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8Y(img,y0,y1,y)
1282 #define cimg_for_in8YC(img,y0,c0,y1,c1,y,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8Y(img,y0,y1,y)
1283 #define cimg_for_in8ZC(img,z0,c0,z1,c1,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8Z(img,z0,z1,z)
1284 #define cimg_for_in8XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8XY(img,x0,y0,x1,y1,x,y)
1285 #define cimg_for_in8XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8XZ(img,x0,y0,x1,y1,x,z)
1286 #define cimg_for_in8YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8YZ(img,y0,z0,y1,z1,y,z)
1287 #define cimg_for_in8XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \
1288  cimg_for_in8C(img,c0,c1,c) cimg_for_in8XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
1289 
1290 #define cimg_for9(bound,i) \
1291  for (int i = 0, _p4##i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
1292  _n1##i = 1>=(int)(bound)?(int)(bound) - 1:1, \
1293  _n2##i = 2>=(int)(bound)?(int)(bound) - 1:2, \
1294  _n3##i = 3>=(int)(bound)?(int)(bound) - 1:3, \
1295  _n4##i = 4>=(int)(bound)?(int)(bound) - 1:4; \
1296  _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
1297  i==(_n4##i = _n3##i = _n2##i = --_n1##i); \
1298  _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
1299 #define cimg_for9X(img,x) cimg_for9((img)._width,x)
1300 #define cimg_for9Y(img,y) cimg_for9((img)._height,y)
1301 #define cimg_for9Z(img,z) cimg_for9((img)._depth,z)
1302 #define cimg_for9C(img,c) cimg_for9((img)._spectrum,c)
1303 #define cimg_for9XY(img,x,y) cimg_for9Y(img,y) cimg_for9X(img,x)
1304 #define cimg_for9XZ(img,x,z) cimg_for9Z(img,z) cimg_for9X(img,x)
1305 #define cimg_for9XC(img,x,c) cimg_for9C(img,c) cimg_for9X(img,x)
1306 #define cimg_for9YZ(img,y,z) cimg_for9Z(img,z) cimg_for9Y(img,y)
1307 #define cimg_for9YC(img,y,c) cimg_for9C(img,c) cimg_for9Y(img,y)
1308 #define cimg_for9ZC(img,z,c) cimg_for9C(img,c) cimg_for9Z(img,z)
1309 #define cimg_for9XYZ(img,x,y,z) cimg_for9Z(img,z) cimg_for9XY(img,x,y)
1310 #define cimg_for9XZC(img,x,z,c) cimg_for9C(img,c) cimg_for9XZ(img,x,z)
1311 #define cimg_for9YZC(img,y,z,c) cimg_for9C(img,c) cimg_for9YZ(img,y,z)
1312 #define cimg_for9XYZC(img,x,y,z,c) cimg_for9C(img,c) cimg_for9XYZ(img,x,y,z)
1313 
1314 #define cimg_for_in9(bound,i0,i1,i) \
1315  for (int i = (int)(i0)<0?0:(int)(i0), \
1316  _p4##i = i - 4<0?0:i - 4, \
1317  _p3##i = i - 3<0?0:i - 3, \
1318  _p2##i = i - 2<0?0:i - 2, \
1319  _p1##i = i - 1<0?0:i - 1, \
1320  _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \
1321  _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \
1322  _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3, \
1323  _n4##i = i + 4>=(int)(bound)?(int)(bound) - 1:i + 4; \
1324  i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
1325  i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \
1326  _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
1327 #define cimg_for_in9X(img,x0,x1,x) cimg_for_in9((img)._width,x0,x1,x)
1328 #define cimg_for_in9Y(img,y0,y1,y) cimg_for_in9((img)._height,y0,y1,y)
1329 #define cimg_for_in9Z(img,z0,z1,z) cimg_for_in9((img)._depth,z0,z1,z)
1330 #define cimg_for_in9C(img,c0,c1,c) cimg_for_in9((img)._spectrum,c0,c1,c)
1331 #define cimg_for_in9XY(img,x0,y0,x1,y1,x,y) cimg_for_in9Y(img,y0,y1,y) cimg_for_in9X(img,x0,x1,x)
1332 #define cimg_for_in9XZ(img,x0,z0,x1,z1,x,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9X(img,x0,x1,x)
1333 #define cimg_for_in9XC(img,x0,c0,x1,c1,x,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9X(img,x0,x1,x)
1334 #define cimg_for_in9YZ(img,y0,z0,y1,z1,y,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9Y(img,y0,y1,y)
1335 #define cimg_for_in9YC(img,y0,c0,y1,c1,y,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9Y(img,y0,y1,y)
1336 #define cimg_for_in9ZC(img,z0,c0,z1,c1,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9Z(img,z0,z1,z)
1337 #define cimg_for_in9XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9XY(img,x0,y0,x1,y1,x,y)
1338 #define cimg_for_in9XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9XZ(img,x0,y0,x1,y1,x,z)
1339 #define cimg_for_in9YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9YZ(img,y0,z0,y1,z1,y,z)
1340 #define cimg_for_in9XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \
1341  cimg_for_in9C(img,c0,c1,c) cimg_for_in9XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
1342 
1343 #define cimg_for2x2(img,x,y,z,c,I,T) \
1344  cimg_for2((img)._height,y) for (int x = 0, \
1345  _n1##x = (int)( \
1346  (I[0] = (T)(img)(0,y,z,c)), \
1347  (I[2] = (T)(img)(0,_n1##y,z,c)), \
1348  1>=(img)._width?(img).width() - 1:1); \
1349  (_n1##x<(img).width() && ( \
1350  (I[1] = (T)(img)(_n1##x,y,z,c)), \
1351  (I[3] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \
1352  x==--_n1##x; \
1353  I[0] = I[1], \
1354  I[2] = I[3], \
1355  ++x, ++_n1##x)
1356 
1357 #define cimg_for_in2x2(img,x0,y0,x1,y1,x,y,z,c,I,T) \
1358  cimg_for_in2((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1359  _n1##x = (int)( \
1360  (I[0] = (T)(img)(x,y,z,c)), \
1361  (I[2] = (T)(img)(x,_n1##y,z,c)), \
1362  x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \
1363  x<=(int)(x1) && ((_n1##x<(img).width() && ( \
1364  (I[1] = (T)(img)(_n1##x,y,z,c)), \
1365  (I[3] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \
1366  x==--_n1##x); \
1367  I[0] = I[1], \
1368  I[2] = I[3], \
1369  ++x, ++_n1##x)
1370 
1371 #define cimg_for3x3(img,x,y,z,c,I,T) \
1372  cimg_for3((img)._height,y) for (int x = 0, \
1373  _p1##x = 0, \
1374  _n1##x = (int)( \
1375  (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \
1376  (I[3] = I[4] = (T)(img)(0,y,z,c)), \
1377  (I[6] = I[7] = (T)(img)(0,_n1##y,z,c)), \
1378  1>=(img)._width?(img).width() - 1:1); \
1379  (_n1##x<(img).width() && ( \
1380  (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \
1381  (I[5] = (T)(img)(_n1##x,y,z,c)), \
1382  (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \
1383  x==--_n1##x; \
1384  I[0] = I[1], I[1] = I[2], \
1385  I[3] = I[4], I[4] = I[5], \
1386  I[6] = I[7], I[7] = I[8], \
1387  _p1##x = x++, ++_n1##x)
1388 
1389 #define cimg_for_in3x3(img,x0,y0,x1,y1,x,y,z,c,I,T) \
1390  cimg_for_in3((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1391  _p1##x = x - 1<0?0:x - 1, \
1392  _n1##x = (int)( \
1393  (I[0] = (T)(img)(_p1##x,_p1##y,z,c)), \
1394  (I[3] = (T)(img)(_p1##x,y,z,c)), \
1395  (I[6] = (T)(img)(_p1##x,_n1##y,z,c)), \
1396  (I[1] = (T)(img)(x,_p1##y,z,c)), \
1397  (I[4] = (T)(img)(x,y,z,c)), \
1398  (I[7] = (T)(img)(x,_n1##y,z,c)), \
1399  x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \
1400  x<=(int)(x1) && ((_n1##x<(img).width() && ( \
1401  (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \
1402  (I[5] = (T)(img)(_n1##x,y,z,c)), \
1403  (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \
1404  x==--_n1##x); \
1405  I[0] = I[1], I[1] = I[2], \
1406  I[3] = I[4], I[4] = I[5], \
1407  I[6] = I[7], I[7] = I[8], \
1408  _p1##x = x++, ++_n1##x)
1409 
1410 #define cimg_for4x4(img,x,y,z,c,I,T) \
1411  cimg_for4((img)._height,y) for (int x = 0, \
1412  _p1##x = 0, \
1413  _n1##x = 1>=(img)._width?(img).width() - 1:1, \
1414  _n2##x = (int)( \
1415  (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \
1416  (I[4] = I[5] = (T)(img)(0,y,z,c)), \
1417  (I[8] = I[9] = (T)(img)(0,_n1##y,z,c)), \
1418  (I[12] = I[13] = (T)(img)(0,_n2##y,z,c)), \
1419  (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \
1420  (I[6] = (T)(img)(_n1##x,y,z,c)), \
1421  (I[10] = (T)(img)(_n1##x,_n1##y,z,c)), \
1422  (I[14] = (T)(img)(_n1##x,_n2##y,z,c)), \
1423  2>=(img)._width?(img).width() - 1:2); \
1424  (_n2##x<(img).width() && ( \
1425  (I[3] = (T)(img)(_n2##x,_p1##y,z,c)), \
1426  (I[7] = (T)(img)(_n2##x,y,z,c)), \
1427  (I[11] = (T)(img)(_n2##x,_n1##y,z,c)), \
1428  (I[15] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \
1429  _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \
1430  I[0] = I[1], I[1] = I[2], I[2] = I[3], \
1431  I[4] = I[5], I[5] = I[6], I[6] = I[7], \
1432  I[8] = I[9], I[9] = I[10], I[10] = I[11], \
1433  I[12] = I[13], I[13] = I[14], I[14] = I[15], \
1434  _p1##x = x++, ++_n1##x, ++_n2##x)
1435 
1436 #define cimg_for_in4x4(img,x0,y0,x1,y1,x,y,z,c,I,T) \
1437  cimg_for_in4((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1438  _p1##x = x - 1<0?0:x - 1, \
1439  _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \
1440  _n2##x = (int)( \
1441  (I[0] = (T)(img)(_p1##x,_p1##y,z,c)), \
1442  (I[4] = (T)(img)(_p1##x,y,z,c)), \
1443  (I[8] = (T)(img)(_p1##x,_n1##y,z,c)), \
1444  (I[12] = (T)(img)(_p1##x,_n2##y,z,c)), \
1445  (I[1] = (T)(img)(x,_p1##y,z,c)), \
1446  (I[5] = (T)(img)(x,y,z,c)), \
1447  (I[9] = (T)(img)(x,_n1##y,z,c)), \
1448  (I[13] = (T)(img)(x,_n2##y,z,c)), \
1449  (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \
1450  (I[6] = (T)(img)(_n1##x,y,z,c)), \
1451  (I[10] = (T)(img)(_n1##x,_n1##y,z,c)), \
1452  (I[14] = (T)(img)(_n1##x,_n2##y,z,c)), \
1453  x + 2>=(int)(img)._width?(img).width() - 1:x + 2); \
1454  x<=(int)(x1) && ((_n2##x<(img).width() && ( \
1455  (I[3] = (T)(img)(_n2##x,_p1##y,z,c)), \
1456  (I[7] = (T)(img)(_n2##x,y,z,c)), \
1457  (I[11] = (T)(img)(_n2##x,_n1##y,z,c)), \
1458  (I[15] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \
1459  _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \
1460  I[0] = I[1], I[1] = I[2], I[2] = I[3], \
1461  I[4] = I[5], I[5] = I[6], I[6] = I[7], \
1462  I[8] = I[9], I[9] = I[10], I[10] = I[11], \
1463  I[12] = I[13], I[13] = I[14], I[14] = I[15], \
1464  _p1##x = x++, ++_n1##x, ++_n2##x)
1465 
1466 #define cimg_for5x5(img,x,y,z,c,I,T) \
1467  cimg_for5((img)._height,y) for (int x = 0, \
1468  _p2##x = 0, _p1##x = 0, \
1469  _n1##x = 1>=(img)._width?(img).width() - 1:1, \
1470  _n2##x = (int)( \
1471  (I[0] = I[1] = I[2] = (T)(img)(_p2##x,_p2##y,z,c)), \
1472  (I[5] = I[6] = I[7] = (T)(img)(0,_p1##y,z,c)), \
1473  (I[10] = I[11] = I[12] = (T)(img)(0,y,z,c)), \
1474  (I[15] = I[16] = I[17] = (T)(img)(0,_n1##y,z,c)), \
1475  (I[20] = I[21] = I[22] = (T)(img)(0,_n2##y,z,c)), \
1476  (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \
1477  (I[8] = (T)(img)(_n1##x,_p1##y,z,c)), \
1478  (I[13] = (T)(img)(_n1##x,y,z,c)), \
1479  (I[18] = (T)(img)(_n1##x,_n1##y,z,c)), \
1480  (I[23] = (T)(img)(_n1##x,_n2##y,z,c)), \
1481  2>=(img)._width?(img).width() - 1:2); \
1482  (_n2##x<(img).width() && ( \
1483  (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \
1484  (I[9] = (T)(img)(_n2##x,_p1##y,z,c)), \
1485  (I[14] = (T)(img)(_n2##x,y,z,c)), \
1486  (I[19] = (T)(img)(_n2##x,_n1##y,z,c)), \
1487  (I[24] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \
1488  _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \
1489  I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \
1490  I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \
1491  I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \
1492  I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \
1493  I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
1494  _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)
1495 
1496 #define cimg_for_in5x5(img,x0,y0,x1,y1,x,y,z,c,I,T) \
1497  cimg_for_in5((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1498  _p2##x = x - 2<0?0:x - 2, \
1499  _p1##x = x - 1<0?0:x - 1, \
1500  _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \
1501  _n2##x = (int)( \
1502  (I[0] = (T)(img)(_p2##x,_p2##y,z,c)), \
1503  (I[5] = (T)(img)(_p2##x,_p1##y,z,c)), \
1504  (I[10] = (T)(img)(_p2##x,y,z,c)), \
1505  (I[15] = (T)(img)(_p2##x,_n1##y,z,c)), \
1506  (I[20] = (T)(img)(_p2##x,_n2##y,z,c)), \
1507  (I[1] = (T)(img)(_p1##x,_p2##y,z,c)), \
1508  (I[6] = (T)(img)(_p1##x,_p1##y,z,c)), \
1509  (I[11] = (T)(img)(_p1##x,y,z,c)), \
1510  (I[16] = (T)(img)(_p1##x,_n1##y,z,c)), \
1511  (I[21] = (T)(img)(_p1##x,_n2##y,z,c)), \
1512  (I[2] = (T)(img)(x,_p2##y,z,c)), \
1513  (I[7] = (T)(img)(x,_p1##y,z,c)), \
1514  (I[12] = (T)(img)(x,y,z,c)), \
1515  (I[17] = (T)(img)(x,_n1##y,z,c)), \
1516  (I[22] = (T)(img)(x,_n2##y,z,c)), \
1517  (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \
1518  (I[8] = (T)(img)(_n1##x,_p1##y,z,c)), \
1519  (I[13] = (T)(img)(_n1##x,y,z,c)), \
1520  (I[18] = (T)(img)(_n1##x,_n1##y,z,c)), \
1521  (I[23] = (T)(img)(_n1##x,_n2##y,z,c)), \
1522  x + 2>=(int)(img)._width?(img).width() - 1:x + 2); \
1523  x<=(int)(x1) && ((_n2##x<(img).width() && ( \
1524  (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \
1525  (I[9] = (T)(img)(_n2##x,_p1##y,z,c)), \
1526  (I[14] = (T)(img)(_n2##x,y,z,c)), \
1527  (I[19] = (T)(img)(_n2##x,_n1##y,z,c)), \
1528  (I[24] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \
1529  _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \
1530  I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \
1531  I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \
1532  I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \
1533  I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \
1534  I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
1535  _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)
1536 
1537 #define cimg_for6x6(img,x,y,z,c,I,T) \
1538  cimg_for6((img)._height,y) for (int x = 0, \
1539  _p2##x = 0, _p1##x = 0, \
1540  _n1##x = 1>=(img)._width?(img).width() - 1:1, \
1541  _n2##x = 2>=(img)._width?(img).width() - 1:2, \
1542  _n3##x = (int)( \
1543  (I[0] = I[1] = I[2] = (T)(img)(_p2##x,_p2##y,z,c)), \
1544  (I[6] = I[7] = I[8] = (T)(img)(0,_p1##y,z,c)), \
1545  (I[12] = I[13] = I[14] = (T)(img)(0,y,z,c)), \
1546  (I[18] = I[19] = I[20] = (T)(img)(0,_n1##y,z,c)), \
1547  (I[24] = I[25] = I[26] = (T)(img)(0,_n2##y,z,c)), \
1548  (I[30] = I[31] = I[32] = (T)(img)(0,_n3##y,z,c)), \
1549  (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \
1550  (I[9] = (T)(img)(_n1##x,_p1##y,z,c)), \
1551  (I[15] = (T)(img)(_n1##x,y,z,c)), \
1552  (I[21] = (T)(img)(_n1##x,_n1##y,z,c)), \
1553  (I[27] = (T)(img)(_n1##x,_n2##y,z,c)), \
1554  (I[33] = (T)(img)(_n1##x,_n3##y,z,c)), \
1555  (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \
1556  (I[10] = (T)(img)(_n2##x,_p1##y,z,c)), \
1557  (I[16] = (T)(img)(_n2##x,y,z,c)), \
1558  (I[22] = (T)(img)(_n2##x,_n1##y,z,c)), \
1559  (I[28] = (T)(img)(_n2##x,_n2##y,z,c)), \
1560  (I[34] = (T)(img)(_n2##x,_n3##y,z,c)), \
1561  3>=(img)._width?(img).width() - 1:3); \
1562  (_n3##x<(img).width() && ( \
1563  (I[5] = (T)(img)(_n3##x,_p2##y,z,c)), \
1564  (I[11] = (T)(img)(_n3##x,_p1##y,z,c)), \
1565  (I[17] = (T)(img)(_n3##x,y,z,c)), \
1566  (I[23] = (T)(img)(_n3##x,_n1##y,z,c)), \
1567  (I[29] = (T)(img)(_n3##x,_n2##y,z,c)), \
1568  (I[35] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \
1569  _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x); \
1570  I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \
1571  I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \
1572  I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
1573  I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
1574  I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \
1575  I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
1576  _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
1577 
1578 #define cimg_for_in6x6(img,x0,y0,x1,y1,x,y,z,c,I,T) \
1579  cimg_for_in6((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)x0, \
1580  _p2##x = x - 2<0?0:x - 2, \
1581  _p1##x = x - 1<0?0:x - 1, \
1582  _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \
1583  _n2##x = x + 2>=(int)(img)._width?(img).width() - 1:x + 2, \
1584  _n3##x = (int)( \
1585  (I[0] = (T)(img)(_p2##x,_p2##y,z,c)), \
1586  (I[6] = (T)(img)(_p2##x,_p1##y,z,c)), \
1587  (I[12] = (T)(img)(_p2##x,y,z,c)), \
1588  (I[18] = (T)(img)(_p2##x,_n1##y,z,c)), \
1589  (I[24] = (T)(img)(_p2##x,_n2##y,z,c)), \
1590  (I[30] = (T)(img)(_p2##x,_n3##y,z,c)), \
1591  (I[1] = (T)(img)(_p1##x,_p2##y,z,c)), \
1592  (I[7] = (T)(img)(_p1##x,_p1##y,z,c)), \
1593  (I[13] = (T)(img)(_p1##x,y,z,c)), \
1594  (I[19] = (T)(img)(_p1##x,_n1##y,z,c)), \
1595  (I[25] = (T)(img)(_p1##x,_n2##y,z,c)), \
1596  (I[31] = (T)(img)(_p1##x,_n3##y,z,c)), \
1597  (I[2] = (T)(img)(x,_p2##y,z,c)), \
1598  (I[8] = (T)(img)(x,_p1##y,z,c)), \
1599  (I[14] = (T)(img)(x,y,z,c)), \
1600  (I[20] = (T)(img)(x,_n1##y,z,c)), \
1601  (I[26] = (T)(img)(x,_n2##y,z,c)), \
1602  (I[32] = (T)(img)(x,_n3##y,z,c)), \
1603  (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \
1604  (I[9] = (T)(img)(_n1##x,_p1##y,z,c)), \
1605  (I[15] = (T)(img)(_n1##x,y,z,c)), \
1606  (I[21] = (T)(img)(_n1##x,_n1##y,z,c)), \
1607  (I[27] = (T)(img)(_n1##x,_n2##y,z,c)), \
1608  (I[33] = (T)(img)(_n1##x,_n3##y,z,c)), \
1609  (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \
1610  (I[10] = (T)(img)(_n2##x,_p1##y,z,c)), \
1611  (I[16] = (T)(img)(_n2##x,y,z,c)), \
1612  (I[22] = (T)(img)(_n2##x,_n1##y,z,c)), \
1613  (I[28] = (T)(img)(_n2##x,_n2##y,z,c)), \
1614  (I[34] = (T)(img)(_n2##x,_n3##y,z,c)), \
1615  x + 3>=(int)(img)._width?(img).width() - 1:x + 3); \
1616  x<=(int)(x1) && ((_n3##x<(img).width() && ( \
1617  (I[5] = (T)(img)(_n3##x,_p2##y,z,c)), \
1618  (I[11] = (T)(img)(_n3##x,_p1##y,z,c)), \
1619  (I[17] = (T)(img)(_n3##x,y,z,c)), \
1620  (I[23] = (T)(img)(_n3##x,_n1##y,z,c)), \
1621  (I[29] = (T)(img)(_n3##x,_n2##y,z,c)), \
1622  (I[35] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \
1623  _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x)); \
1624  I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \
1625  I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \
1626  I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
1627  I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
1628  I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \
1629  I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
1630  _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
1631 
1632 #define cimg_for7x7(img,x,y,z,c,I,T) \
1633  cimg_for7((img)._height,y) for (int x = 0, \
1634  _p3##x = 0, _p2##x = 0, _p1##x = 0, \
1635  _n1##x = 1>=(img)._width?(img).width() - 1:1, \
1636  _n2##x = 2>=(img)._width?(img).width() - 1:2, \
1637  _n3##x = (int)( \
1638  (I[0] = I[1] = I[2] = I[3] = (T)(img)(_p3##x,_p3##y,z,c)), \
1639  (I[7] = I[8] = I[9] = I[10] = (T)(img)(0,_p2##y,z,c)), \
1640  (I[14] = I[15] = I[16] = I[17] = (T)(img)(0,_p1##y,z,c)), \
1641  (I[21] = I[22] = I[23] = I[24] = (T)(img)(0,y,z,c)), \
1642  (I[28] = I[29] = I[30] = I[31] = (T)(img)(0,_n1##y,z,c)), \
1643  (I[35] = I[36] = I[37] = I[38] = (T)(img)(0,_n2##y,z,c)), \
1644  (I[42] = I[43] = I[44] = I[45] = (T)(img)(0,_n3##y,z,c)), \
1645  (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \
1646  (I[11] = (T)(img)(_n1##x,_p2##y,z,c)), \
1647  (I[18] = (T)(img)(_n1##x,_p1##y,z,c)), \
1648  (I[25] = (T)(img)(_n1##x,y,z,c)), \
1649  (I[32] = (T)(img)(_n1##x,_n1##y,z,c)), \
1650  (I[39] = (T)(img)(_n1##x,_n2##y,z,c)), \
1651  (I[46] = (T)(img)(_n1##x,_n3##y,z,c)), \
1652  (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \
1653  (I[12] = (T)(img)(_n2##x,_p2##y,z,c)), \
1654  (I[19] = (T)(img)(_n2##x,_p1##y,z,c)), \
1655  (I[26] = (T)(img)(_n2##x,y,z,c)), \
1656  (I[33] = (T)(img)(_n2##x,_n1##y,z,c)), \
1657  (I[40] = (T)(img)(_n2##x,_n2##y,z,c)), \
1658  (I[47] = (T)(img)(_n2##x,_n3##y,z,c)), \
1659  3>=(img)._width?(img).width() - 1:3); \
1660  (_n3##x<(img).width() && ( \
1661  (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \
1662  (I[13] = (T)(img)(_n3##x,_p2##y,z,c)), \
1663  (I[20] = (T)(img)(_n3##x,_p1##y,z,c)), \
1664  (I[27] = (T)(img)(_n3##x,y,z,c)), \
1665  (I[34] = (T)(img)(_n3##x,_n1##y,z,c)), \
1666  (I[41] = (T)(img)(_n3##x,_n2##y,z,c)), \
1667  (I[48] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \
1668  _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x); \
1669  I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \
1670  I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \
1671  I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \
1672  I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \
1673  I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \
1674  I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \
1675  I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
1676  _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
1677 
1678 #define cimg_for_in7x7(img,x0,y0,x1,y1,x,y,z,c,I,T) \
1679  cimg_for_in7((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1680  _p3##x = x - 3<0?0:x - 3, \
1681  _p2##x = x - 2<0?0:x - 2, \
1682  _p1##x = x - 1<0?0:x - 1, \
1683  _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \
1684  _n2##x = x + 2>=(int)(img)._width?(img).width() - 1:x + 2, \
1685  _n3##x = (int)( \
1686  (I[0] = (T)(img)(_p3##x,_p3##y,z,c)), \
1687  (I[7] = (T)(img)(_p3##x,_p2##y,z,c)), \
1688  (I[14] = (T)(img)(_p3##x,_p1##y,z,c)), \
1689  (I[21] = (T)(img)(_p3##x,y,z,c)), \
1690  (I[28] = (T)(img)(_p3##x,_n1##y,z,c)), \
1691  (I[35] = (T)(img)(_p3##x,_n2##y,z,c)), \
1692  (I[42] = (T)(img)(_p3##x,_n3##y,z,c)), \
1693  (I[1] = (T)(img)(_p2##x,_p3##y,z,c)), \
1694  (I[8] = (T)(img)(_p2##x,_p2##y,z,c)), \
1695  (I[15] = (T)(img)(_p2##x,_p1##y,z,c)), \
1696  (I[22] = (T)(img)(_p2##x,y,z,c)), \
1697  (I[29] = (T)(img)(_p2##x,_n1##y,z,c)), \
1698  (I[36] = (T)(img)(_p2##x,_n2##y,z,c)), \
1699  (I[43] = (T)(img)(_p2##x,_n3##y,z,c)), \
1700  (I[2] = (T)(img)(_p1##x,_p3##y,z,c)), \
1701  (I[9] = (T)(img)(_p1##x,_p2##y,z,c)), \
1702  (I[16] = (T)(img)(_p1##x,_p1##y,z,c)), \
1703  (I[23] = (T)(img)(_p1##x,y,z,c)), \
1704  (I[30] = (T)(img)(_p1##x,_n1##y,z,c)), \
1705  (I[37] = (T)(img)(_p1##x,_n2##y,z,c)), \
1706  (I[44] = (T)(img)(_p1##x,_n3##y,z,c)), \
1707  (I[3] = (T)(img)(x,_p3##y,z,c)), \
1708  (I[10] = (T)(img)(x,_p2##y,z,c)), \
1709  (I[17] = (T)(img)(x,_p1##y,z,c)), \
1710  (I[24] = (T)(img)(x,y,z,c)), \
1711  (I[31] = (T)(img)(x,_n1##y,z,c)), \
1712  (I[38] = (T)(img)(x,_n2##y,z,c)), \
1713  (I[45] = (T)(img)(x,_n3##y,z,c)), \
1714  (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \
1715  (I[11] = (T)(img)(_n1##x,_p2##y,z,c)), \
1716  (I[18] = (T)(img)(_n1##x,_p1##y,z,c)), \
1717  (I[25] = (T)(img)(_n1##x,y,z,c)), \
1718  (I[32] = (T)(img)(_n1##x,_n1##y,z,c)), \
1719  (I[39] = (T)(img)(_n1##x,_n2##y,z,c)), \
1720  (I[46] = (T)(img)(_n1##x,_n3##y,z,c)), \
1721  (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \
1722  (I[12] = (T)(img)(_n2##x,_p2##y,z,c)), \
1723  (I[19] = (T)(img)(_n2##x,_p1##y,z,c)), \
1724  (I[26] = (T)(img)(_n2##x,y,z,c)), \
1725  (I[33] = (T)(img)(_n2##x,_n1##y,z,c)), \
1726  (I[40] = (T)(img)(_n2##x,_n2##y,z,c)), \
1727  (I[47] = (T)(img)(_n2##x,_n3##y,z,c)), \
1728  x + 3>=(int)(img)._width?(img).width() - 1:x + 3); \
1729  x<=(int)(x1) && ((_n3##x<(img).width() && ( \
1730  (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \
1731  (I[13] = (T)(img)(_n3##x,_p2##y,z,c)), \
1732  (I[20] = (T)(img)(_n3##x,_p1##y,z,c)), \
1733  (I[27] = (T)(img)(_n3##x,y,z,c)), \
1734  (I[34] = (T)(img)(_n3##x,_n1##y,z,c)), \
1735  (I[41] = (T)(img)(_n3##x,_n2##y,z,c)), \
1736  (I[48] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \
1737  _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x)); \
1738  I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \
1739  I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \
1740  I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \
1741  I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \
1742  I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \
1743  I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \
1744  I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
1745  _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
1746 
1747 #define cimg_for8x8(img,x,y,z,c,I,T) \
1748  cimg_for8((img)._height,y) for (int x = 0, \
1749  _p3##x = 0, _p2##x = 0, _p1##x = 0, \
1750  _n1##x = 1>=((img)._width)?(img).width() - 1:1, \
1751  _n2##x = 2>=((img)._width)?(img).width() - 1:2, \
1752  _n3##x = 3>=((img)._width)?(img).width() - 1:3, \
1753  _n4##x = (int)( \
1754  (I[0] = I[1] = I[2] = I[3] = (T)(img)(_p3##x,_p3##y,z,c)), \
1755  (I[8] = I[9] = I[10] = I[11] = (T)(img)(0,_p2##y,z,c)), \
1756  (I[16] = I[17] = I[18] = I[19] = (T)(img)(0,_p1##y,z,c)), \
1757  (I[24] = I[25] = I[26] = I[27] = (T)(img)(0,y,z,c)), \
1758  (I[32] = I[33] = I[34] = I[35] = (T)(img)(0,_n1##y,z,c)), \
1759  (I[40] = I[41] = I[42] = I[43] = (T)(img)(0,_n2##y,z,c)), \
1760  (I[48] = I[49] = I[50] = I[51] = (T)(img)(0,_n3##y,z,c)), \
1761  (I[56] = I[57] = I[58] = I[59] = (T)(img)(0,_n4##y,z,c)), \
1762  (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \
1763  (I[12] = (T)(img)(_n1##x,_p2##y,z,c)), \
1764  (I[20] = (T)(img)(_n1##x,_p1##y,z,c)), \
1765  (I[28] = (T)(img)(_n1##x,y,z,c)), \
1766  (I[36] = (T)(img)(_n1##x,_n1##y,z,c)), \
1767  (I[44] = (T)(img)(_n1##x,_n2##y,z,c)), \
1768  (I[52] = (T)(img)(_n1##x,_n3##y,z,c)), \
1769  (I[60] = (T)(img)(_n1##x,_n4##y,z,c)), \
1770  (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \
1771  (I[13] = (T)(img)(_n2##x,_p2##y,z,c)), \
1772  (I[21] = (T)(img)(_n2##x,_p1##y,z,c)), \
1773  (I[29] = (T)(img)(_n2##x,y,z,c)), \
1774  (I[37] = (T)(img)(_n2##x,_n1##y,z,c)), \
1775  (I[45] = (T)(img)(_n2##x,_n2##y,z,c)), \
1776  (I[53] = (T)(img)(_n2##x,_n3##y,z,c)), \
1777  (I[61] = (T)(img)(_n2##x,_n4##y,z,c)), \
1778  (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \
1779  (I[14] = (T)(img)(_n3##x,_p2##y,z,c)), \
1780  (I[22] = (T)(img)(_n3##x,_p1##y,z,c)), \
1781  (I[30] = (T)(img)(_n3##x,y,z,c)), \
1782  (I[38] = (T)(img)(_n3##x,_n1##y,z,c)), \
1783  (I[46] = (T)(img)(_n3##x,_n2##y,z,c)), \
1784  (I[54] = (T)(img)(_n3##x,_n3##y,z,c)), \
1785  (I[62] = (T)(img)(_n3##x,_n4##y,z,c)), \
1786  4>=((img)._width)?(img).width() - 1:4); \
1787  (_n4##x<(img).width() && ( \
1788  (I[7] = (T)(img)(_n4##x,_p3##y,z,c)), \
1789  (I[15] = (T)(img)(_n4##x,_p2##y,z,c)), \
1790  (I[23] = (T)(img)(_n4##x,_p1##y,z,c)), \
1791  (I[31] = (T)(img)(_n4##x,y,z,c)), \
1792  (I[39] = (T)(img)(_n4##x,_n1##y,z,c)), \
1793  (I[47] = (T)(img)(_n4##x,_n2##y,z,c)), \
1794  (I[55] = (T)(img)(_n4##x,_n3##y,z,c)), \
1795  (I[63] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \
1796  _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \
1797  I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], \
1798  I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], \
1799  I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
1800  I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], \
1801  I[32] = I[33], I[33] = I[34], I[34] = I[35], I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], \
1802  I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], \
1803  I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[53] = I[54], I[54] = I[55], \
1804  I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[62] = I[63], \
1805  _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
1806 
1807 #define cimg_for_in8x8(img,x0,y0,x1,y1,x,y,z,c,I,T) \
1808  cimg_for_in8((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1809  _p3##x = x - 3<0?0:x - 3, \
1810  _p2##x = x - 2<0?0:x - 2, \
1811  _p1##x = x - 1<0?0:x - 1, \
1812  _n1##x = x + 1>=(img).width()?(img).width() - 1:x + 1, \
1813  _n2##x = x + 2>=(img).width()?(img).width() - 1:x + 2, \
1814  _n3##x = x + 3>=(img).width()?(img).width() - 1:x + 3, \
1815  _n4##x = (int)( \
1816  (I[0] = (T)(img)(_p3##x,_p3##y,z,c)), \
1817  (I[8] = (T)(img)(_p3##x,_p2##y,z,c)), \
1818  (I[16] = (T)(img)(_p3##x,_p1##y,z,c)), \
1819  (I[24] = (T)(img)(_p3##x,y,z,c)), \
1820  (I[32] = (T)(img)(_p3##x,_n1##y,z,c)), \
1821  (I[40] = (T)(img)(_p3##x,_n2##y,z,c)), \
1822  (I[48] = (T)(img)(_p3##x,_n3##y,z,c)), \
1823  (I[56] = (T)(img)(_p3##x,_n4##y,z,c)), \
1824  (I[1] = (T)(img)(_p2##x,_p3##y,z,c)), \
1825  (I[9] = (T)(img)(_p2##x,_p2##y,z,c)), \
1826  (I[17] = (T)(img)(_p2##x,_p1##y,z,c)), \
1827  (I[25] = (T)(img)(_p2##x,y,z,c)), \
1828  (I[33] = (T)(img)(_p2##x,_n1##y,z,c)), \
1829  (I[41] = (T)(img)(_p2##x,_n2##y,z,c)), \
1830  (I[49] = (T)(img)(_p2##x,_n3##y,z,c)), \
1831  (I[57] = (T)(img)(_p2##x,_n4##y,z,c)), \
1832  (I[2] = (T)(img)(_p1##x,_p3##y,z,c)), \
1833  (I[10] = (T)(img)(_p1##x,_p2##y,z,c)), \
1834  (I[18] = (T)(img)(_p1##x,_p1##y,z,c)), \
1835  (I[26] = (T)(img)(_p1##x,y,z,c)), \
1836  (I[34] = (T)(img)(_p1##x,_n1##y,z,c)), \
1837  (I[42] = (T)(img)(_p1##x,_n2##y,z,c)), \
1838  (I[50] = (T)(img)(_p1##x,_n3##y,z,c)), \
1839  (I[58] = (T)(img)(_p1##x,_n4##y,z,c)), \
1840  (I[3] = (T)(img)(x,_p3##y,z,c)), \
1841  (I[11] = (T)(img)(x,_p2##y,z,c)), \
1842  (I[19] = (T)(img)(x,_p1##y,z,c)), \
1843  (I[27] = (T)(img)(x,y,z,c)), \
1844  (I[35] = (T)(img)(x,_n1##y,z,c)), \
1845  (I[43] = (T)(img)(x,_n2##y,z,c)), \
1846  (I[51] = (T)(img)(x,_n3##y,z,c)), \
1847  (I[59] = (T)(img)(x,_n4##y,z,c)), \
1848  (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \
1849  (I[12] = (T)(img)(_n1##x,_p2##y,z,c)), \
1850  (I[20] = (T)(img)(_n1##x,_p1##y,z,c)), \
1851  (I[28] = (T)(img)(_n1##x,y,z,c)), \
1852  (I[36] = (T)(img)(_n1##x,_n1##y,z,c)), \
1853  (I[44] = (T)(img)(_n1##x,_n2##y,z,c)), \
1854  (I[52] = (T)(img)(_n1##x,_n3##y,z,c)), \
1855  (I[60] = (T)(img)(_n1##x,_n4##y,z,c)), \
1856  (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \
1857  (I[13] = (T)(img)(_n2##x,_p2##y,z,c)), \
1858  (I[21] = (T)(img)(_n2##x,_p1##y,z,c)), \
1859  (I[29] = (T)(img)(_n2##x,y,z,c)), \
1860  (I[37] = (T)(img)(_n2##x,_n1##y,z,c)), \
1861  (I[45] = (T)(img)(_n2##x,_n2##y,z,c)), \
1862  (I[53] = (T)(img)(_n2##x,_n3##y,z,c)), \
1863  (I[61] = (T)(img)(_n2##x,_n4##y,z,c)), \
1864  (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \
1865  (I[14] = (T)(img)(_n3##x,_p2##y,z,c)), \
1866  (I[22] = (T)(img)(_n3##x,_p1##y,z,c)), \
1867  (I[30] = (T)(img)(_n3##x,y,z,c)), \
1868  (I[38] = (T)(img)(_n3##x,_n1##y,z,c)), \
1869  (I[46] = (T)(img)(_n3##x,_n2##y,z,c)), \
1870  (I[54] = (T)(img)(_n3##x,_n3##y,z,c)), \
1871  (I[62] = (T)(img)(_n3##x,_n4##y,z,c)), \
1872  x + 4>=(img).width()?(img).width() - 1:x + 4); \
1873  x<=(int)(x1) && ((_n4##x<(img).width() && ( \
1874  (I[7] = (T)(img)(_n4##x,_p3##y,z,c)), \
1875  (I[15] = (T)(img)(_n4##x,_p2##y,z,c)), \
1876  (I[23] = (T)(img)(_n4##x,_p1##y,z,c)), \
1877  (I[31] = (T)(img)(_n4##x,y,z,c)), \
1878  (I[39] = (T)(img)(_n4##x,_n1##y,z,c)), \
1879  (I[47] = (T)(img)(_n4##x,_n2##y,z,c)), \
1880  (I[55] = (T)(img)(_n4##x,_n3##y,z,c)), \
1881  (I[63] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \
1882  _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \
1883  I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], \
1884  I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], \
1885  I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
1886  I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], \
1887  I[32] = I[33], I[33] = I[34], I[34] = I[35], I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], \
1888  I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], \
1889  I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[53] = I[54], I[54] = I[55], \
1890  I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[62] = I[63], \
1891  _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
1892 
1893 #define cimg_for9x9(img,x,y,z,c,I,T) \
1894  cimg_for9((img)._height,y) for (int x = 0, \
1895  _p4##x = 0, _p3##x = 0, _p2##x = 0, _p1##x = 0, \
1896  _n1##x = 1>=((img)._width)?(img).width() - 1:1, \
1897  _n2##x = 2>=((img)._width)?(img).width() - 1:2, \
1898  _n3##x = 3>=((img)._width)?(img).width() - 1:3, \
1899  _n4##x = (int)( \
1900  (I[0] = I[1] = I[2] = I[3] = I[4] = (T)(img)(_p4##x,_p4##y,z,c)), \
1901  (I[9] = I[10] = I[11] = I[12] = I[13] = (T)(img)(0,_p3##y,z,c)), \
1902  (I[18] = I[19] = I[20] = I[21] = I[22] = (T)(img)(0,_p2##y,z,c)), \
1903  (I[27] = I[28] = I[29] = I[30] = I[31] = (T)(img)(0,_p1##y,z,c)), \
1904  (I[36] = I[37] = I[38] = I[39] = I[40] = (T)(img)(0,y,z,c)), \
1905  (I[45] = I[46] = I[47] = I[48] = I[49] = (T)(img)(0,_n1##y,z,c)), \
1906  (I[54] = I[55] = I[56] = I[57] = I[58] = (T)(img)(0,_n2##y,z,c)), \
1907  (I[63] = I[64] = I[65] = I[66] = I[67] = (T)(img)(0,_n3##y,z,c)), \
1908  (I[72] = I[73] = I[74] = I[75] = I[76] = (T)(img)(0,_n4##y,z,c)), \
1909  (I[5] = (T)(img)(_n1##x,_p4##y,z,c)), \
1910  (I[14] = (T)(img)(_n1##x,_p3##y,z,c)), \
1911  (I[23] = (T)(img)(_n1##x,_p2##y,z,c)), \
1912  (I[32] = (T)(img)(_n1##x,_p1##y,z,c)), \
1913  (I[41] = (T)(img)(_n1##x,y,z,c)), \
1914  (I[50] = (T)(img)(_n1##x,_n1##y,z,c)), \
1915  (I[59] = (T)(img)(_n1##x,_n2##y,z,c)), \
1916  (I[68] = (T)(img)(_n1##x,_n3##y,z,c)), \
1917  (I[77] = (T)(img)(_n1##x,_n4##y,z,c)), \
1918  (I[6] = (T)(img)(_n2##x,_p4##y,z,c)), \
1919  (I[15] = (T)(img)(_n2##x,_p3##y,z,c)), \
1920  (I[24] = (T)(img)(_n2##x,_p2##y,z,c)), \
1921  (I[33] = (T)(img)(_n2##x,_p1##y,z,c)), \
1922  (I[42] = (T)(img)(_n2##x,y,z,c)), \
1923  (I[51] = (T)(img)(_n2##x,_n1##y,z,c)), \
1924  (I[60] = (T)(img)(_n2##x,_n2##y,z,c)), \
1925  (I[69] = (T)(img)(_n2##x,_n3##y,z,c)), \
1926  (I[78] = (T)(img)(_n2##x,_n4##y,z,c)), \
1927  (I[7] = (T)(img)(_n3##x,_p4##y,z,c)), \
1928  (I[16] = (T)(img)(_n3##x,_p3##y,z,c)), \
1929  (I[25] = (T)(img)(_n3##x,_p2##y,z,c)), \
1930  (I[34] = (T)(img)(_n3##x,_p1##y,z,c)), \
1931  (I[43] = (T)(img)(_n3##x,y,z,c)), \
1932  (I[52] = (T)(img)(_n3##x,_n1##y,z,c)), \
1933  (I[61] = (T)(img)(_n3##x,_n2##y,z,c)), \
1934  (I[70] = (T)(img)(_n3##x,_n3##y,z,c)), \
1935  (I[79] = (T)(img)(_n3##x,_n4##y,z,c)), \
1936  4>=((img)._width)?(img).width() - 1:4); \
1937  (_n4##x<(img).width() && ( \
1938  (I[8] = (T)(img)(_n4##x,_p4##y,z,c)), \
1939  (I[17] = (T)(img)(_n4##x,_p3##y,z,c)), \
1940  (I[26] = (T)(img)(_n4##x,_p2##y,z,c)), \
1941  (I[35] = (T)(img)(_n4##x,_p1##y,z,c)), \
1942  (I[44] = (T)(img)(_n4##x,y,z,c)), \
1943  (I[53] = (T)(img)(_n4##x,_n1##y,z,c)), \
1944  (I[62] = (T)(img)(_n4##x,_n2##y,z,c)), \
1945  (I[71] = (T)(img)(_n4##x,_n3##y,z,c)), \
1946  (I[80] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \
1947  _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \
1948  I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], I[7] = I[8], \
1949  I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], \
1950  I[16] = I[17], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
1951  I[24] = I[25], I[25] = I[26], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], \
1952  I[32] = I[33], I[33] = I[34], I[34] = I[35], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], \
1953  I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
1954  I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[54] = I[55], I[55] = I[56], \
1955  I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[63] = I[64], \
1956  I[64] = I[65], I[65] = I[66], I[66] = I[67], I[67] = I[68], I[68] = I[69], I[69] = I[70], I[70] = I[71], \
1957  I[72] = I[73], I[73] = I[74], I[74] = I[75], I[75] = I[76], I[76] = I[77], I[77] = I[78], I[78] = I[79], \
1958  I[79] = I[80], \
1959  _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
1960 
1961 #define cimg_for_in9x9(img,x0,y0,x1,y1,x,y,z,c,I,T) \
1962  cimg_for_in9((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1963  _p4##x = x - 4<0?0:x - 4, \
1964  _p3##x = x - 3<0?0:x - 3, \
1965  _p2##x = x - 2<0?0:x - 2, \
1966  _p1##x = x - 1<0?0:x - 1, \
1967  _n1##x = x + 1>=(img).width()?(img).width() - 1:x + 1, \
1968  _n2##x = x + 2>=(img).width()?(img).width() - 1:x + 2, \
1969  _n3##x = x + 3>=(img).width()?(img).width() - 1:x + 3, \
1970  _n4##x = (int)( \
1971  (I[0] = (T)(img)(_p4##x,_p4##y,z,c)), \
1972  (I[9] = (T)(img)(_p4##x,_p3##y,z,c)), \
1973  (I[18] = (T)(img)(_p4##x,_p2##y,z,c)), \
1974  (I[27] = (T)(img)(_p4##x,_p1##y,z,c)), \
1975  (I[36] = (T)(img)(_p4##x,y,z,c)), \
1976  (I[45] = (T)(img)(_p4##x,_n1##y,z,c)), \
1977  (I[54] = (T)(img)(_p4##x,_n2##y,z,c)), \
1978  (I[63] = (T)(img)(_p4##x,_n3##y,z,c)), \
1979  (I[72] = (T)(img)(_p4##x,_n4##y,z,c)), \
1980  (I[1] = (T)(img)(_p3##x,_p4##y,z,c)), \
1981  (I[10] = (T)(img)(_p3##x,_p3##y,z,c)), \
1982  (I[19] = (T)(img)(_p3##x,_p2##y,z,c)), \
1983  (I[28] = (T)(img)(_p3##x,_p1##y,z,c)), \
1984  (I[37] = (T)(img)(_p3##x,y,z,c)), \
1985  (I[46] = (T)(img)(_p3##x,_n1##y,z,c)), \
1986  (I[55] = (T)(img)(_p3##x,_n2##y,z,c)), \
1987  (I[64] = (T)(img)(_p3##x,_n3##y,z,c)), \
1988  (I[73] = (T)(img)(_p3##x,_n4##y,z,c)), \
1989  (I[2] = (T)(img)(_p2##x,_p4##y,z,c)), \
1990  (I[11] = (T)(img)(_p2##x,_p3##y,z,c)), \
1991  (I[20] = (T)(img)(_p2##x,_p2##y,z,c)), \
1992  (I[29] = (T)(img)(_p2##x,_p1##y,z,c)), \
1993  (I[38] = (T)(img)(_p2##x,y,z,c)), \
1994  (I[47] = (T)(img)(_p2##x,_n1##y,z,c)), \
1995  (I[56] = (T)(img)(_p2##x,_n2##y,z,c)), \
1996  (I[65] = (T)(img)(_p2##x,_n3##y,z,c)), \
1997  (I[74] = (T)(img)(_p2##x,_n4##y,z,c)), \
1998  (I[3] = (T)(img)(_p1##x,_p4##y,z,c)), \
1999  (I[12] = (T)(img)(_p1##x,_p3##y,z,c)), \
2000  (I[21] = (T)(img)(_p1##x,_p2##y,z,c)), \
2001  (I[30] = (T)(img)(_p1##x,_p1##y,z,c)), \
2002  (I[39] = (T)(img)(_p1##x,y,z,c)), \
2003  (I[48] = (T)(img)(_p1##x,_n1##y,z,c)), \
2004  (I[57] = (T)(img)(_p1##x,_n2##y,z,c)), \
2005  (I[66] = (T)(img)(_p1##x,_n3##y,z,c)), \
2006  (I[75] = (T)(img)(_p1##x,_n4##y,z,c)), \
2007  (I[4] = (T)(img)(x,_p4##y,z,c)), \
2008  (I[13] = (T)(img)(x,_p3##y,z,c)), \
2009  (I[22] = (T)(img)(x,_p2##y,z,c)), \
2010  (I[31] = (T)(img)(x,_p1##y,z,c)), \
2011  (I[40] = (T)(img)(x,y,z,c)), \
2012  (I[49] = (T)(img)(x,_n1##y,z,c)), \
2013  (I[58] = (T)(img)(x,_n2##y,z,c)), \
2014  (I[67] = (T)(img)(x,_n3##y,z,c)), \
2015  (I[76] = (T)(img)(x,_n4##y,z,c)), \
2016  (I[5] = (T)(img)(_n1##x,_p4##y,z,c)), \
2017  (I[14] = (T)(img)(_n1##x,_p3##y,z,c)), \
2018  (I[23] = (T)(img)(_n1##x,_p2##y,z,c)), \
2019  (I[32] = (T)(img)(_n1##x,_p1##y,z,c)), \
2020  (I[41] = (T)(img)(_n1##x,y,z,c)), \
2021  (I[50] = (T)(img)(_n1##x,_n1##y,z,c)), \
2022  (I[59] = (T)(img)(_n1##x,_n2##y,z,c)), \
2023  (I[68] = (T)(img)(_n1##x,_n3##y,z,c)), \
2024  (I[77] = (T)(img)(_n1##x,_n4##y,z,c)), \
2025  (I[6] = (T)(img)(_n2##x,_p4##y,z,c)), \
2026  (I[15] = (T)(img)(_n2##x,_p3##y,z,c)), \
2027  (I[24] = (T)(img)(_n2##x,_p2##y,z,c)), \
2028  (I[33] = (T)(img)(_n2##x,_p1##y,z,c)), \
2029  (I[42] = (T)(img)(_n2##x,y,z,c)), \
2030  (I[51] = (T)(img)(_n2##x,_n1##y,z,c)), \
2031  (I[60] = (T)(img)(_n2##x,_n2##y,z,c)), \
2032  (I[69] = (T)(img)(_n2##x,_n3##y,z,c)), \
2033  (I[78] = (T)(img)(_n2##x,_n4##y,z,c)), \
2034  (I[7] = (T)(img)(_n3##x,_p4##y,z,c)), \
2035  (I[16] = (T)(img)(_n3##x,_p3##y,z,c)), \
2036  (I[25] = (T)(img)(_n3##x,_p2##y,z,c)), \
2037  (I[34] = (T)(img)(_n3##x,_p1##y,z,c)), \
2038  (I[43] = (T)(img)(_n3##x,y,z,c)), \
2039  (I[52] = (T)(img)(_n3##x,_n1##y,z,c)), \
2040  (I[61] = (T)(img)(_n3##x,_n2##y,z,c)), \
2041  (I[70] = (T)(img)(_n3##x,_n3##y,z,c)), \
2042  (I[79] = (T)(img)(_n3##x,_n4##y,z,c)), \
2043  x + 4>=(img).width()?(img).width() - 1:x + 4); \
2044  x<=(int)(x1) && ((_n4##x<(img).width() && ( \
2045  (I[8] = (T)(img)(_n4##x,_p4##y,z,c)), \
2046  (I[17] = (T)(img)(_n4##x,_p3##y,z,c)), \
2047  (I[26] = (T)(img)(_n4##x,_p2##y,z,c)), \
2048  (I[35] = (T)(img)(_n4##x,_p1##y,z,c)), \
2049  (I[44] = (T)(img)(_n4##x,y,z,c)), \
2050  (I[53] = (T)(img)(_n4##x,_n1##y,z,c)), \
2051  (I[62] = (T)(img)(_n4##x,_n2##y,z,c)), \
2052  (I[71] = (T)(img)(_n4##x,_n3##y,z,c)), \
2053  (I[80] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \
2054  _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \
2055  I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], I[7] = I[8], \
2056  I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], \
2057  I[16] = I[17], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
2058  I[24] = I[25], I[25] = I[26], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], \
2059  I[32] = I[33], I[33] = I[34], I[34] = I[35], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], \
2060  I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
2061  I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[54] = I[55], I[55] = I[56], \
2062  I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[63] = I[64], \
2063  I[64] = I[65], I[65] = I[66], I[66] = I[67], I[67] = I[68], I[68] = I[69], I[69] = I[70], I[70] = I[71], \
2064  I[72] = I[73], I[73] = I[74], I[74] = I[75], I[75] = I[76], I[76] = I[77], I[77] = I[78], I[78] = I[79], \
2065  I[79] = I[80], \
2066  _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
2067 
2068 #define cimg_for2x2x2(img,x,y,z,c,I,T) \
2069  cimg_for2((img)._depth,z) cimg_for2((img)._height,y) for (int x = 0, \
2070  _n1##x = (int)( \
2071  (I[0] = (T)(img)(0,y,z,c)), \
2072  (I[2] = (T)(img)(0,_n1##y,z,c)), \
2073  (I[4] = (T)(img)(0,y,_n1##z,c)), \
2074  (I[6] = (T)(img)(0,_n1##y,_n1##z,c)), \
2075  1>=(img)._width?(img).width() - 1:1); \
2076  (_n1##x<(img).width() && ( \
2077  (I[1] = (T)(img)(_n1##x,y,z,c)), \
2078  (I[3] = (T)(img)(_n1##x,_n1##y,z,c)), \
2079  (I[5] = (T)(img)(_n1##x,y,_n1##z,c)), \
2080  (I[7] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \
2081  x==--_n1##x; \
2082  I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \
2083  ++x, ++_n1##x)
2084 
2085 #define cimg_for_in2x2x2(img,x0,y0,z0,x1,y1,z1,x,y,z,c,I,T) \
2086  cimg_for_in2((img)._depth,z0,z1,z) cimg_for_in2((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
2087  _n1##x = (int)( \
2088  (I[0] = (T)(img)(x,y,z,c)), \
2089  (I[2] = (T)(img)(x,_n1##y,z,c)), \
2090  (I[4] = (T)(img)(x,y,_n1##z,c)), \
2091  (I[6] = (T)(img)(x,_n1##y,_n1##z,c)), \
2092  x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \
2093  x<=(int)(x1) && ((_n1##x<(img).width() && ( \
2094  (I[1] = (T)(img)(_n1##x,y,z,c)), \
2095  (I[3] = (T)(img)(_n1##x,_n1##y,z,c)), \
2096  (I[5] = (T)(img)(_n1##x,y,_n1##z,c)), \
2097  (I[7] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \
2098  x==--_n1##x); \
2099  I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \
2100  ++x, ++_n1##x)
2101 
2102 #define cimg_for3x3x3(img,x,y,z,c,I,T) \
2103  cimg_for3((img)._depth,z) cimg_for3((img)._height,y) for (int x = 0, \
2104  _p1##x = 0, \
2105  _n1##x = (int)( \
2106  (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,_p1##z,c)), \
2107  (I[3] = I[4] = (T)(img)(0,y,_p1##z,c)), \
2108  (I[6] = I[7] = (T)(img)(0,_n1##y,_p1##z,c)), \
2109  (I[9] = I[10] = (T)(img)(0,_p1##y,z,c)), \
2110  (I[12] = I[13] = (T)(img)(0,y,z,c)), \
2111  (I[15] = I[16] = (T)(img)(0,_n1##y,z,c)), \
2112  (I[18] = I[19] = (T)(img)(0,_p1##y,_n1##z,c)), \
2113  (I[21] = I[22] = (T)(img)(0,y,_n1##z,c)), \
2114  (I[24] = I[25] = (T)(img)(0,_n1##y,_n1##z,c)), \
2115  1>=(img)._width?(img).width() - 1:1); \
2116  (_n1##x<(img).width() && ( \
2117  (I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c)), \
2118  (I[5] = (T)(img)(_n1##x,y,_p1##z,c)), \
2119  (I[8] = (T)(img)(_n1##x,_n1##y,_p1##z,c)), \
2120  (I[11] = (T)(img)(_n1##x,_p1##y,z,c)), \
2121  (I[14] = (T)(img)(_n1##x,y,z,c)), \
2122  (I[17] = (T)(img)(_n1##x,_n1##y,z,c)), \
2123  (I[20] = (T)(img)(_n1##x,_p1##y,_n1##z,c)), \
2124  (I[23] = (T)(img)(_n1##x,y,_n1##z,c)), \
2125  (I[26] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \
2126  x==--_n1##x; \
2127  I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \
2128  I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \
2129  I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \
2130  _p1##x = x++, ++_n1##x)
2131 
2132 #define cimg_for_in3x3x3(img,x0,y0,z0,x1,y1,z1,x,y,z,c,I,T) \
2133  cimg_for_in3((img)._depth,z0,z1,z) cimg_for_in3((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
2134  _p1##x = x - 1<0?0:x - 1, \
2135  _n1##x = (int)( \
2136  (I[0] = (T)(img)(_p1##x,_p1##y,_p1##z,c)), \
2137  (I[3] = (T)(img)(_p1##x,y,_p1##z,c)), \
2138  (I[6] = (T)(img)(_p1##x,_n1##y,_p1##z,c)), \
2139  (I[9] = (T)(img)(_p1##x,_p1##y,z,c)), \
2140  (I[12] = (T)(img)(_p1##x,y,z,c)), \
2141  (I[15] = (T)(img)(_p1##x,_n1##y,z,c)), \
2142  (I[18] = (T)(img)(_p1##x,_p1##y,_n1##z,c)), \
2143  (I[21] = (T)(img)(_p1##x,y,_n1##z,c)), \
2144  (I[24] = (T)(img)(_p1##x,_n1##y,_n1##z,c)), \
2145  (I[1] = (T)(img)(x,_p1##y,_p1##z,c)), \
2146  (I[4] = (T)(img)(x,y,_p1##z,c)), \
2147  (I[7] = (T)(img)(x,_n1##y,_p1##z,c)), \
2148  (I[10] = (T)(img)(x,_p1##y,z,c)), \
2149  (I[13] = (T)(img)(x,y,z,c)), \
2150  (I[16] = (T)(img)(x,_n1##y,z,c)), \
2151  (I[19] = (T)(img)(x,_p1##y,_n1##z,c)), \
2152  (I[22] = (T)(img)(x,y,_n1##z,c)), \
2153  (I[25] = (T)(img)(x,_n1##y,_n1##z,c)), \
2154  x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \
2155  x<=(int)(x1) && ((_n1##x<(img).width() && ( \
2156  (I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c)), \
2157  (I[5] = (T)(img)(_n1##x,y,_p1##z,c)), \
2158  (I[8] = (T)(img)(_n1##x,_n1##y,_p1##z,c)), \
2159  (I[11] = (T)(img)(_n1##x,_p1##y,z,c)), \
2160  (I[14] = (T)(img)(_n1##x,y,z,c)), \
2161  (I[17] = (T)(img)(_n1##x,_n1##y,z,c)), \
2162  (I[20] = (T)(img)(_n1##x,_p1##y,_n1##z,c)), \
2163  (I[23] = (T)(img)(_n1##x,y,_n1##z,c)), \
2164  (I[26] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \
2165  x==--_n1##x); \
2166  I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \
2167  I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \
2168  I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \
2169  _p1##x = x++, ++_n1##x)
2170 
2171 #define cimglist_for(list,l) for (int l = 0; l<(int)(list)._width; ++l)
2172 #define cimglist_for_in(list,l0,l1,l) \
2173  for (int l = (int)(l0)<0?0:(int)(l0), _max##l = (unsigned int)l1<(list)._width?(int)(l1):(int)(list)._width - 1; \
2174  l<=_max##l; ++l)
2175 
2176 #define cimglist_apply(list,fn) cimglist_for(list,__##fn) (list)[__##fn].fn
2177 
2178 // Macros used to display error messages when exceptions are thrown.
2179 // You should not use these macros is your own code.
2180 #define _cimgdisplay_instance "[instance(%u,%u,%u,%c%s%c)] CImgDisplay::"
2181 #define cimgdisplay_instance _width,_height,_normalization,_title?'\"':'[',_title?_title:"untitled",_title?'\"':']'
2182 #define _cimg_instance "[instance(%u,%u,%u,%u,%p,%sshared)] CImg<%s>::"
2183 #define cimg_instance _width,_height,_depth,_spectrum,_data,_is_shared?"":"non-",pixel_type()
2184 #define _cimglist_instance "[instance(%u,%u,%p)] CImgList<%s>::"
2185 #define cimglist_instance _width,_allocated_width,_data,pixel_type()
2186 
2187 /*------------------------------------------------
2188  #
2189  #
2190  # Define cimg_library:: namespace
2191  #
2192  #
2193  -------------------------------------------------*/
2195 
2207 
2208  // Declare the four classes of the CImg Library.
2209  template<typename T=float> struct CImg;
2210  template<typename T=float> struct CImgList;
2211  struct CImgDisplay;
2212  struct CImgException;
2213 
2214  // Declare cimg:: namespace.
2215  // This is an uncomplete namespace definition here. It only contains some
2216  // necessary stuff to ensure a correct declaration order of the classes and functions
2217  // defined afterwards.
2218  namespace cimg {
2219 
2220  // Define ascii sequences for colored terminal output.
2221 #ifdef cimg_use_vt100
2222  static const char t_normal[] = { 0x1b, '[', '0', ';', '0', ';', '0', 'm', 0 };
2223  static const char t_black[] = { 0x1b, '[', '0', ';', '3', '0', ';', '5', '9', 'm', 0 };
2224  static const char t_red[] = { 0x1b, '[', '0', ';', '3', '1', ';', '5', '9', 'm', 0 };
2225  static const char t_green[] = { 0x1b, '[', '0', ';', '3', '2', ';', '5', '9', 'm', 0 };
2226  static const char t_yellow[] = { 0x1b, '[', '0', ';', '3', '3', ';', '5', '9', 'm', 0 };
2227  static const char t_blue[] = { 0x1b, '[', '0', ';', '3', '4', ';', '5', '9', 'm', 0 };
2228  static const char t_magenta[] = { 0x1b, '[', '0', ';', '3', '5', ';', '5', '9', 'm', 0 };
2229  static const char t_cyan[] = { 0x1b, '[', '0', ';', '3', '6', ';', '5', '9', 'm', 0 };
2230  static const char t_white[] = { 0x1b, '[', '0', ';', '3', '7', ';', '5', '9', 'm', 0 };
2231  static const char t_bold[] = { 0x1b, '[', '1', 'm', 0 };
2232  static const char t_underscore[] = { 0x1b, '[', '4', 'm', 0 };
2233 #else
2234  static const char t_normal[] = { 0 };
2235  static const char *const t_black = cimg::t_normal,
2236  *const t_red = cimg::t_normal,
2237  *const t_green = cimg::t_normal,
2238  *const t_yellow = cimg::t_normal,
2239  *const t_blue = cimg::t_normal,
2240  *const t_magenta = cimg::t_normal,
2241  *const t_cyan = cimg::t_normal,
2242  *const t_white = cimg::t_normal,
2243  *const t_bold = cimg::t_normal,
2244  *const t_underscore = cimg::t_normal;
2245 #endif
2246 
2247  inline std::FILE* output(std::FILE *file=0);
2248  inline void info();
2249 
2251  template<typename T>
2252  inline void unused(const T&, ...) {}
2253 
2254  // [internal] Lock/unlock a mutex for managing concurrent threads.
2255  // 'lock_mode' can be { 0=unlock | 1=lock | 2=trylock }.
2256  // 'n' can be in [0,31] but mutex range [0,15] is reserved by CImg.
2257  inline int mutex(const unsigned int n, const int lock_mode=1);
2258 
2259  inline unsigned int& _exception_mode(const unsigned int value, const bool is_set) {
2260  static unsigned int mode = cimg_verbosity;
2261  if (is_set) { cimg::mutex(0); mode = value<4?value:4; cimg::mutex(0,0); }
2262  return mode;
2263  }
2264 
2265  // Functions to return standard streams 'stdin', 'stdout' and 'stderr'.
2266  inline FILE* _stdin(const bool throw_exception=true);
2267  inline FILE* _stdout(const bool throw_exception=true);
2268  inline FILE* _stderr(const bool throw_exception=true);
2269 
2270  // Mandatory because Microsoft's _snprintf() and _vsnprintf() do not add the '\0' character
2271  // at the end of the string.
2272 #if cimg_OS==2 && defined(_MSC_VER)
2273  inline int _snprintf(char *const s, const size_t size, const char *const format, ...) {
2274  va_list ap;
2275  va_start(ap,format);
2276  const int result = _vsnprintf(s,size,format,ap);
2277  va_end(ap);
2278  return result;
2279  }
2280 
2281  inline int _vsnprintf(char *const s, const size_t size, const char *const format, va_list ap) {
2282  int result = -1;
2283  cimg::mutex(6);
2284  if (size) result = _vsnprintf_s(s,size,_TRUNCATE,format,ap);
2285  if (result==-1) result = _vscprintf(format,ap);
2286  cimg::mutex(6,0);
2287  return result;
2288  }
2289 
2290  // Mutex-protected version of sscanf, sprintf and snprintf.
2291  // Used only MacOSX, as it seems those functions are not re-entrant on MacOSX.
2292 #elif defined(__MACOSX__) || defined(__APPLE__)
2293  inline int _sscanf(const char *const s, const char *const format, ...) {
2294  cimg::mutex(6);
2295  va_list args;
2296  va_start(args,format);
2297  const int result = std::vsscanf(s,format,args);
2298  va_end(args);
2299  cimg::mutex(6,0);
2300  return result;
2301  }
2302 
2303  inline int _sprintf(char *const s, const char *const format, ...) {
2304  cimg::mutex(6);
2305  va_list args;
2306  va_start(args,format);
2307  const int result = std::vsprintf(s,format,args);
2308  va_end(args);
2309  cimg::mutex(6,0);
2310  return result;
2311  }
2312 
2313  inline int _snprintf(char *const s, const size_t n, const char *const format, ...) {
2314  cimg::mutex(6);
2315  va_list args;
2316  va_start(args,format);
2317  const int result = std::vsnprintf(s,n,format,args);
2318  va_end(args);
2319  cimg::mutex(6,0);
2320  return result;
2321  }
2322 
2323  inline int _vsnprintf(char *const s, const size_t size, const char* format, va_list ap) {
2324  cimg::mutex(6);
2325  const int result = std::vsnprintf(s,size,format,ap);
2326  cimg::mutex(6,0);
2327  return result;
2328  }
2329 #endif
2330 
2332 
2341  inline unsigned int& exception_mode(const unsigned int mode) {
2342  return _exception_mode(mode,true);
2343  }
2344 
2346 
2349  inline unsigned int& exception_mode() {
2350  return _exception_mode(0,false);
2351  }
2352 
2354 
2361  inline unsigned int& _openmp_mode(const unsigned int value, const bool is_set) {
2362  static unsigned int mode = 2;
2363  if (is_set) { cimg::mutex(0); mode = value<2?value:2; cimg::mutex(0,0); }
2364  return mode;
2365  }
2366 
2367  inline unsigned int& openmp_mode(const unsigned int mode) {
2368  return _openmp_mode(mode,true);
2369  }
2370 
2372  inline unsigned int& openmp_mode() {
2373  return _openmp_mode(0,false);
2374  }
2375 
2376 #define cimg_openmp_if(cond) if (cimg::openmp_mode()==1 || (cimg::openmp_mode()>1 && (cond)))
2377 
2378  // Display a simple dialog box, and wait for the user's response.
2379  inline int dialog(const char *const title, const char *const msg, const char *const button1_label="OK",
2380  const char *const button2_label=0, const char *const button3_label=0,
2381  const char *const button4_label=0, const char *const button5_label=0,
2382  const char *const button6_label=0, const bool centering=false);
2383 
2384  // Evaluate math expression.
2385  inline double eval(const char *const expression,
2386  const double x=0, const double y=0, const double z=0, const double c=0);
2387 
2388  }
2389 
2390  /*---------------------------------------
2391  #
2392  # Define the CImgException structures
2393  #
2394  --------------------------------------*/
2396 
2460  struct CImgException : public std::exception {
2461 #define _cimg_exception_err(etype,disp_flag) \
2462  std::va_list ap, ap2; \
2463  va_start(ap,format); va_start(ap2,format); \
2464  int size = cimg_vsnprintf(0,0,format,ap2); \
2465  if (size++>=0) { \
2466  delete[] _message; \
2467  _message = new char[size]; \
2468  cimg_vsnprintf(_message,size,format,ap); \
2469  if (cimg::exception_mode()) { \
2470  std::fprintf(cimg::output(),"\n%s[CImg] *** %s ***%s %s\n",cimg::t_red,etype,cimg::t_normal,_message); \
2471  if (cimg_display && disp_flag && !(cimg::exception_mode()%2)) try { cimg::dialog(etype,_message,"Abort"); } \
2472  catch (CImgException&) {} \
2473  if (cimg::exception_mode()>=3) cimg_library_suffixed::cimg::info(); \
2474  } \
2475  } \
2476  va_end(ap); va_end(ap2); \
2477 
2478  char *_message;
2479  CImgException() { _message = new char[1]; *_message = 0; }
2480  CImgException(const char *const format, ...):_message(0) { _cimg_exception_err("CImgException",true); }
2481  CImgException(const CImgException& e):std::exception(e) {
2482  const size_t size = std::strlen(e._message);
2483  _message = new char[size + 1];
2484  std::strncpy(_message,e._message,size);
2485  _message[size] = 0;
2486  }
2487  ~CImgException() throw() { delete[] _message; }
2488  CImgException& operator=(const CImgException& e) {
2489  const size_t size = std::strlen(e._message);
2490  _message = new char[size + 1];
2491  std::strncpy(_message,e._message,size);
2492  _message[size] = 0;
2493  return *this;
2494  }
2496  const char *what() const throw() { return _message; }
2497  };
2498 
2499  // The CImgAbortException class is used to throw an exception when
2500  // a computationally-intensive function has been aborted by an external signal.
2501  struct CImgAbortException : public std::exception {
2502  char *_message;
2503  CImgAbortException() { _message = new char[1]; *_message = 0; }
2504  CImgAbortException(const char *const format, ...):_message(0) { _cimg_exception_err("CImgAbortException",true); }
2505  CImgAbortException(const CImgAbortException& e):std::exception(e) {
2506  const size_t size = std::strlen(e._message);
2507  _message = new char[size + 1];
2508  std::strncpy(_message,e._message,size);
2509  _message[size] = 0;
2510  }
2511  ~CImgAbortException() throw() { delete[] _message; }
2512  CImgAbortException& operator=(const CImgAbortException& e) {
2513  const size_t size = std::strlen(e._message);
2514  _message = new char[size + 1];
2515  std::strncpy(_message,e._message,size);
2516  _message[size] = 0;
2517  return *this;
2518  }
2520  const char *what() const throw() { return _message; }
2521  };
2522 
2523  // The CImgArgumentException class is used to throw an exception related
2524  // to invalid arguments encountered in a library function call.
2526  CImgArgumentException(const char *const format, ...) { _cimg_exception_err("CImgArgumentException",true); }
2527  };
2528 
2529  // The CImgDisplayException class is used to throw an exception related
2530  // to display problems encountered in a library function call.
2532  CImgDisplayException(const char *const format, ...) { _cimg_exception_err("CImgDisplayException",false); }
2533  };
2534 
2535  // The CImgInstanceException class is used to throw an exception related
2536  // to an invalid instance encountered in a library function call.
2538  CImgInstanceException(const char *const format, ...) { _cimg_exception_err("CImgInstanceException",true); }
2539  };
2540 
2541  // The CImgIOException class is used to throw an exception related
2542  // to input/output file problems encountered in a library function call.
2543  struct CImgIOException : public CImgException {
2544  CImgIOException(const char *const format, ...) { _cimg_exception_err("CImgIOException",true); }
2545  };
2546 
2547  // The CImgWarningException class is used to throw an exception for warnings
2548  // encountered in a library function call.
2550  CImgWarningException(const char *const format, ...) { _cimg_exception_err("CImgWarningException",false); }
2551  };
2552 
2553  /*-------------------------------------
2554  #
2555  # Define cimg:: namespace
2556  #
2557  -----------------------------------*/
2559 
2566  namespace cimg {
2567 
2568  // Define traits that will be used to determine the best data type to work in CImg functions.
2569  //
2570  template<typename T> struct type {
2571  static const char* string() {
2572  static const char* s[] = { "unknown", "unknown8", "unknown16", "unknown24",
2573  "unknown32", "unknown40", "unknown48", "unknown56",
2574  "unknown64", "unknown72", "unknown80", "unknown88",
2575  "unknown96", "unknown104", "unknown112", "unknown120",
2576  "unknown128" };
2577  return s[(sizeof(T)<17)?sizeof(T):0];
2578  }
2579  static bool is_float() { return false; }
2580  static bool is_inf(const T) { return false; }
2581  static bool is_nan(const T) { return false; }
2582  static T min() { return ~max(); }
2583  static T max() { return (T)1<<(8*sizeof(T) - 1); }
2584  static T inf() { return max(); }
2585  static T cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(T)val; }
2586  static const char* format() { return "%s"; }
2587  static const char* format_s() { return "%s"; }
2588  static const char* format(const T& val) { static const char *const s = "unknown"; cimg::unused(val); return s; }
2589  };
2590 
2591  template<> struct type<bool> {
2592  static const char* string() { static const char *const s = "bool"; return s; }
2593  static bool is_float() { return false; }
2594  static bool is_inf(const bool) { return false; }
2595  static bool is_nan(const bool) { return false; }
2596  static bool min() { return false; }
2597  static bool max() { return true; }
2598  static bool inf() { return max(); }
2599  static bool is_inf() { return false; }
2600  static bool cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(bool)val; }
2601  static const char* format() { return "%s"; }
2602  static const char* format_s() { return "%s"; }
2603  static const char* format(const bool val) { static const char* s[] = { "false", "true" }; return s[val?1:0]; }
2604  };
2605 
2606  template<> struct type<unsigned char> {
2607  static const char* string() { static const char *const s = "unsigned char"; return s; }
2608  static bool is_float() { return false; }
2609  static bool is_inf(const unsigned char) { return false; }
2610  static bool is_nan(const unsigned char) { return false; }
2611  static unsigned char min() { return 0; }
2612  static unsigned char max() { return (unsigned char)-1; }
2613  static unsigned char inf() { return max(); }
2614  static unsigned char cut(const double val) {
2615  return val<(double)min()?min():val>(double)max()?max():(unsigned char)val; }
2616  static const char* format() { return "%u"; }
2617  static const char* format_s() { return "%u"; }
2618  static unsigned int format(const unsigned char val) { return (unsigned int)val; }
2619  };
2620 
2621 #if defined(CHAR_MAX) && CHAR_MAX==255
2622  template<> struct type<char> {
2623  static const char* string() { static const char *const s = "char"; return s; }
2624  static bool is_float() { return false; }
2625  static bool is_inf(const char) { return false; }
2626  static bool is_nan(const char) { return false; }
2627  static char min() { return 0; }
2628  static char max() { return (char)-1; }
2629  static char inf() { return max(); }
2630  static char cut(const double val) {
2631  return val<(double)min()?min():val>(double)max()?max():(unsigned char)val; }
2632  static const char* format() { return "%u"; }
2633  static const char* format_s() { return "%u"; }
2634  static unsigned int format(const char val) { return (unsigned int)val; }
2635  };
2636 #else
2637  template<> struct type<char> {
2638  static const char* string() { static const char *const s = "char"; return s; }
2639  static bool is_float() { return false; }
2640  static bool is_inf(const char) { return false; }
2641  static bool is_nan(const char) { return false; }
2642  static char min() { return ~max(); }
2643  static char max() { return (char)((unsigned char)-1>>1); }
2644  static char inf() { return max(); }
2645  static char cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(char)val; }
2646  static const char* format() { return "%d"; }
2647  static const char* format_s() { return "%d"; }
2648  static int format(const char val) { return (int)val; }
2649  };
2650 #endif
2651 
2652  template<> struct type<signed char> {
2653  static const char* string() { static const char *const s = "signed char"; return s; }
2654  static bool is_float() { return false; }
2655  static bool is_inf(const signed char) { return false; }
2656  static bool is_nan(const signed char) { return false; }
2657  static signed char min() { return ~max(); }
2658  static signed char max() { return (signed char)((unsigned char)-1>>1); }
2659  static signed char inf() { return max(); }
2660  static signed char cut(const double val) {
2661  return val<(double)min()?min():val>(double)max()?max():(signed char)val; }
2662  static const char* format() { return "%d"; }
2663  static const char* format_s() { return "%d"; }
2664  static int format(const signed char val) { return (int)val; }
2665  };
2666 
2667  template<> struct type<unsigned short> {
2668  static const char* string() { static const char *const s = "unsigned short"; return s; }
2669  static bool is_float() { return false; }
2670  static bool is_inf(const unsigned short) { return false; }
2671  static bool is_nan(const unsigned short) { return false; }
2672  static unsigned short min() { return 0; }
2673  static unsigned short max() { return (unsigned short)-1; }
2674  static unsigned short inf() { return max(); }
2675  static unsigned short cut(const double val) {
2676  return val<(double)min()?min():val>(double)max()?max():(unsigned short)val; }
2677  static const char* format() { return "%u"; }
2678  static const char* format_s() { return "%u"; }
2679  static unsigned int format(const unsigned short val) { return (unsigned int)val; }
2680  };
2681 
2682  template<> struct type<short> {
2683  static const char* string() { static const char *const s = "short"; return s; }
2684  static bool is_float() { return false; }
2685  static bool is_inf(const short) { return false; }
2686  static bool is_nan(const short) { return false; }
2687  static short min() { return ~max(); }
2688  static short max() { return (short)((unsigned short)-1>>1); }
2689  static short inf() { return max(); }
2690  static short cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(short)val; }
2691  static const char* format() { return "%d"; }
2692  static const char* format_s() { return "%d"; }
2693  static int format(const short val) { return (int)val; }
2694  };
2695 
2696  template<> struct type<unsigned int> {
2697  static const char* string() { static const char *const s = "unsigned int"; return s; }
2698  static bool is_float() { return false; }
2699  static bool is_inf(const unsigned int) { return false; }
2700  static bool is_nan(const unsigned int) { return false; }
2701  static unsigned int min() { return 0; }
2702  static unsigned int max() { return (unsigned int)-1; }
2703  static unsigned int inf() { return max(); }
2704  static unsigned int cut(const double val) {
2705  return val<(double)min()?min():val>(double)max()?max():(unsigned int)val; }
2706  static const char* format() { return "%u"; }
2707  static const char* format_s() { return "%u"; }
2708  static unsigned int format(const unsigned int val) { return val; }
2709  };
2710 
2711  template<> struct type<int> {
2712  static const char* string() { static const char *const s = "int"; return s; }
2713  static bool is_float() { return false; }
2714  static bool is_inf(const int) { return false; }
2715  static bool is_nan(const int) { return false; }
2716  static int min() { return ~max(); }
2717  static int max() { return (int)((unsigned int)-1>>1); }
2718  static int inf() { return max(); }
2719  static int cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(int)val; }
2720  static const char* format() { return "%d"; }
2721  static const char* format_s() { return "%d"; }
2722  static int format(const int val) { return val; }
2723  };
2724 
2725  template<> struct type<cimg_uint64> {
2726  static const char* string() { static const char *const s = "unsigned int64"; return s; }
2727  static bool is_float() { return false; }
2728  static bool is_inf(const cimg_uint64) { return false; }
2729  static bool is_nan(const cimg_uint64) { return false; }
2730  static cimg_uint64 min() { return 0; }
2731  static cimg_uint64 max() { return (cimg_uint64)-1; }
2732  static cimg_uint64 inf() { return max(); }
2733  static cimg_uint64 cut(const double val) {
2734  return val<(double)min()?min():val>(double)max()?max():(cimg_uint64)val; }
2735  static const char* format() { return cimg_fuint64; }
2736  static const char* format_s() { return cimg_fuint64; }
2737  static unsigned long format(const cimg_uint64 val) { return (unsigned long)val; }
2738  };
2739 
2740  template<> struct type<cimg_int64> {
2741  static const char* string() { static const char *const s = "int64"; return s; }
2742  static bool is_float() { return false; }
2743  static bool is_inf(const cimg_int64) { return false; }
2744  static bool is_nan(const cimg_int64) { return false; }
2745  static cimg_int64 min() { return ~max(); }
2746  static cimg_int64 max() { return (cimg_int64)((cimg_uint64)-1>>1); }
2747  static cimg_int64 inf() { return max(); }
2748  static cimg_int64 cut(const double val) {
2749  return val<(double)min()?min():val>(double)max()?max():(cimg_int64)val;
2750  }
2751  static const char* format() { return cimg_fint64; }
2752  static const char* format_s() { return cimg_fint64; }
2753  static long format(const long val) { return (long)val; }
2754  };
2755 
2756  template<> struct type<double> {
2757  static const char* string() { static const char *const s = "double"; return s; }
2758  static bool is_float() { return true; }
2759  static bool is_inf(const double val) {
2760 #ifdef isinf
2761  return (bool)isinf(val);
2762 #else
2763  return !is_nan(val) && (val<cimg::type<double>::min() || val>cimg::type<double>::max());
2764 #endif
2765  }
2766  static bool is_nan(const double val) {
2767 #ifdef isnan
2768  return (bool)isnan(val);
2769 #else
2770  return !(val==val);
2771 #endif
2772  }
2773  static double min() { return -DBL_MAX; }
2774  static double max() { return DBL_MAX; }
2775  static double inf() {
2776 #ifdef INFINITY
2777  return (double)INFINITY;
2778 #else
2779  return max()*max();
2780 #endif
2781  }
2782  static double nan() {
2783 #ifdef NAN
2784  return (double)NAN;
2785 #else
2786  const double val_nan = -std::sqrt(-1.0); return val_nan;
2787 #endif
2788  }
2789  static double cut(const double val) { return val; }
2790  static const char* format() { return "%.17g"; }
2791  static const char* format_s() { return "%g"; }
2792  static double format(const double val) { return val; }
2793  };
2794 
2795  template<> struct type<float> {
2796  static const char* string() { static const char *const s = "float"; return s; }
2797  static bool is_float() { return true; }
2798  static bool is_inf(const float val) {
2799 #ifdef isinf
2800  return (bool)isinf(val);
2801 #else
2802  return !is_nan(val) && (val<cimg::type<float>::min() || val>cimg::type<float>::max());
2803 #endif
2804  }
2805  static bool is_nan(const float val) {
2806 #ifdef isnan
2807  return (bool)isnan(val);
2808 #else
2809  return !(val==val);
2810 #endif
2811  }
2812  static float min() { return -FLT_MAX; }
2813  static float max() { return FLT_MAX; }
2814  static float inf() { return (float)cimg::type<double>::inf(); }
2815  static float nan() { return (float)cimg::type<double>::nan(); }
2816  static float cut(const double val) { return (float)val; }
2817  static float cut(const float val) { return (float)val; }
2818  static const char* format() { return "%.9g"; }
2819  static const char* format_s() { return "%g"; }
2820  static double format(const float val) { return (double)val; }
2821  };
2822 
2823  template<> struct type<long double> {
2824  static const char* string() { static const char *const s = "long double"; return s; }
2825  static bool is_float() { return true; }
2826  static bool is_inf(const long double val) {
2827 #ifdef isinf
2828  return (bool)isinf(val);
2829 #else
2830  return !is_nan(val) && (val<cimg::type<long double>::min() || val>cimg::type<long double>::max());
2831 #endif
2832  }
2833  static bool is_nan(const long double val) {
2834 #ifdef isnan
2835  return (bool)isnan(val);
2836 #else
2837  return !(val==val);
2838 #endif
2839  }
2840  static long double min() { return -LDBL_MAX; }
2841  static long double max() { return LDBL_MAX; }
2842  static long double inf() { return max()*max(); }
2843  static long double nan() { const long double val_nan = -std::sqrt(-1.0L); return val_nan; }
2844  static long double cut(const long double val) { return val; }
2845  static const char* format() { return "%.17g"; }
2846  static const char* format_s() { return "%g"; }
2847  static double format(const long double val) { return (double)val; }
2848  };
2849 
2850 #ifdef cimg_use_half
2851  template<> struct type<half> {
2852  static const char* string() { static const char *const s = "half"; return s; }
2853  static bool is_float() { return true; }
2854  static bool is_inf(const long double val) {
2855 #ifdef isinf
2856  return (bool)isinf(val);
2857 #else
2858  return !is_nan(val) && (val<cimg::type<half>::min() || val>cimg::type<half>::max());
2859 #endif
2860  }
2861  static bool is_nan(const long double val) {
2862 #ifdef isnan
2863  return (bool)isnan(val);
2864 #else
2865  return !(val==val);
2866 #endif
2867  }
2868  static half min() { return (half)-65504; }
2869  static half max() { return (half)65504; }
2870  static half inf() { return max()*max(); }
2871  static half nan() { const half val_nan = (half)-std::sqrt(-1.0); return val_nan; }
2872  static half cut(const double val) { return (half)val; }
2873  static const char* format() { return "%.9g"; }
2874  static const char* format_s() { return "%g"; }
2875  static double format(const half val) { return (double)val; }
2876  };
2877 #endif
2878 
2879  template<typename T, typename t> struct superset { typedef T type; };
2880  template<> struct superset<bool,unsigned char> { typedef unsigned char type; };
2881  template<> struct superset<bool,char> { typedef char type; };
2882  template<> struct superset<bool,signed char> { typedef signed char type; };
2883  template<> struct superset<bool,unsigned short> { typedef unsigned short type; };
2884  template<> struct superset<bool,short> { typedef short type; };
2885  template<> struct superset<bool,unsigned int> { typedef unsigned int type; };
2886  template<> struct superset<bool,int> { typedef int type; };
2887  template<> struct superset<bool,cimg_uint64> { typedef cimg_uint64 type; };
2888  template<> struct superset<bool,cimg_int64> { typedef cimg_int64 type; };
2889  template<> struct superset<bool,float> { typedef float type; };
2890  template<> struct superset<bool,double> { typedef double type; };
2891  template<> struct superset<unsigned char,char> { typedef short type; };
2892  template<> struct superset<unsigned char,signed char> { typedef short type; };
2893  template<> struct superset<unsigned char,unsigned short> { typedef unsigned short type; };
2894  template<> struct superset<unsigned char,short> { typedef short type; };
2895  template<> struct superset<unsigned char,unsigned int> { typedef unsigned int type; };
2896  template<> struct superset<unsigned char,int> { typedef int type; };
2897  template<> struct superset<unsigned char,cimg_uint64> { typedef cimg_uint64 type; };
2898  template<> struct superset<unsigned char,cimg_int64> { typedef cimg_int64 type; };
2899  template<> struct superset<unsigned char,float> { typedef float type; };
2900  template<> struct superset<unsigned char,double> { typedef double type; };
2901  template<> struct superset<signed char,unsigned char> { typedef short type; };
2902  template<> struct superset<signed char,char> { typedef short type; };
2903  template<> struct superset<signed char,unsigned short> { typedef int type; };
2904  template<> struct superset<signed char,short> { typedef short type; };
2905  template<> struct superset<signed char,unsigned int> { typedef cimg_int64 type; };
2906  template<> struct superset<signed char,int> { typedef int type; };
2907  template<> struct superset<signed char,cimg_uint64> { typedef cimg_int64 type; };
2908  template<> struct superset<signed char,cimg_int64> { typedef cimg_int64 type; };
2909  template<> struct superset<signed char,float> { typedef float type; };
2910  template<> struct superset<signed char,double> { typedef double type; };
2911  template<> struct superset<char,unsigned char> { typedef short type; };
2912  template<> struct superset<char,signed char> { typedef short type; };
2913  template<> struct superset<char,unsigned short> { typedef int type; };
2914  template<> struct superset<char,short> { typedef short type; };
2915  template<> struct superset<char,unsigned int> { typedef cimg_int64 type; };
2916  template<> struct superset<char,int> { typedef int type; };
2917  template<> struct superset<char,cimg_uint64> { typedef cimg_int64 type; };
2918  template<> struct superset<char,cimg_int64> { typedef cimg_int64 type; };
2919  template<> struct superset<char,float> { typedef float type; };
2920  template<> struct superset<char,double> { typedef double type; };
2921  template<> struct superset<unsigned short,char> { typedef int type; };
2922  template<> struct superset<unsigned short,signed char> { typedef int type; };
2923  template<> struct superset<unsigned short,short> { typedef int type; };
2924  template<> struct superset<unsigned short,unsigned int> { typedef unsigned int type; };
2925  template<> struct superset<unsigned short,int> { typedef int type; };
2926  template<> struct superset<unsigned short,cimg_uint64> { typedef cimg_uint64 type; };
2927  template<> struct superset<unsigned short,cimg_int64> { typedef cimg_int64 type; };
2928  template<> struct superset<unsigned short,float> { typedef float type; };
2929  template<> struct superset<unsigned short,double> { typedef double type; };
2930  template<> struct superset<short,unsigned short> { typedef int type; };
2931  template<> struct superset<short,unsigned int> { typedef cimg_int64 type; };
2932  template<> struct superset<short,int> { typedef int type; };
2933  template<> struct superset<short,cimg_uint64> { typedef cimg_int64 type; };
2934  template<> struct superset<short,cimg_int64> { typedef cimg_int64 type; };
2935  template<> struct superset<short,float> { typedef float type; };
2936  template<> struct superset<short,double> { typedef double type; };
2937  template<> struct superset<unsigned int,char> { typedef cimg_int64 type; };
2938  template<> struct superset<unsigned int,signed char> { typedef cimg_int64 type; };
2939  template<> struct superset<unsigned int,short> { typedef cimg_int64 type; };
2940  template<> struct superset<unsigned int,int> { typedef cimg_int64 type; };
2941  template<> struct superset<unsigned int,cimg_uint64> { typedef cimg_uint64 type; };
2942  template<> struct superset<unsigned int,cimg_int64> { typedef cimg_int64 type; };
2943  template<> struct superset<unsigned int,float> { typedef float type; };
2944  template<> struct superset<unsigned int,double> { typedef double type; };
2945  template<> struct superset<int,unsigned int> { typedef cimg_int64 type; };
2946  template<> struct superset<int,cimg_uint64> { typedef cimg_int64 type; };
2947  template<> struct superset<int,cimg_int64> { typedef cimg_int64 type; };
2948  template<> struct superset<int,float> { typedef float type; };
2949  template<> struct superset<int,double> { typedef double type; };
2950  template<> struct superset<cimg_uint64,char> { typedef cimg_int64 type; };
2951  template<> struct superset<cimg_uint64,signed char> { typedef cimg_int64 type; };
2952  template<> struct superset<cimg_uint64,short> { typedef cimg_int64 type; };
2953  template<> struct superset<cimg_uint64,int> { typedef cimg_int64 type; };
2954  template<> struct superset<cimg_uint64,cimg_int64> { typedef cimg_int64 type; };
2955  template<> struct superset<cimg_uint64,float> { typedef double type; };
2956  template<> struct superset<cimg_uint64,double> { typedef double type; };
2957  template<> struct superset<cimg_int64,float> { typedef double type; };
2958  template<> struct superset<cimg_int64,double> { typedef double type; };
2959  template<> struct superset<float,double> { typedef double type; };
2960 #ifdef cimg_use_half
2961  template<> struct superset<half,unsigned short> { typedef float type; };
2962  template<> struct superset<half,short> { typedef float type; };
2963  template<> struct superset<half,unsigned int> { typedef float type; };
2964  template<> struct superset<half,int> { typedef float type; };
2965  template<> struct superset<half,cimg_uint64> { typedef float type; };
2966  template<> struct superset<half,cimg_int64> { typedef float type; };
2967  template<> struct superset<half,float> { typedef float type; };
2968  template<> struct superset<half,double> { typedef double type; };
2969 #endif
2970 
2971  template<typename t1, typename t2, typename t3> struct superset2 {
2972  typedef typename superset<t1, typename superset<t2,t3>::type>::type type;
2973  };
2974 
2975  template<typename t1, typename t2, typename t3, typename t4> struct superset3 {
2976  typedef typename superset<t1, typename superset2<t2,t3,t4>::type>::type type;
2977  };
2978 
2979  template<typename t1, typename t2> struct last { typedef t2 type; };
2980 
2981 #define _cimg_Tt typename cimg::superset<T,t>::type
2982 #define _cimg_Tfloat typename cimg::superset<T,float>::type
2983 #define _cimg_Ttfloat typename cimg::superset2<T,t,float>::type
2984 #define _cimg_Ttdouble typename cimg::superset2<T,t,double>::type
2985 
2986  // Define variables used internally by CImg.
2987 #if cimg_display==1
2988  struct X11_info {
2989  unsigned int nb_wins;
2990  pthread_t *events_thread;
2991  pthread_cond_t wait_event;
2992  pthread_mutex_t wait_event_mutex;
2993  CImgDisplay **wins;
2994  Display *display;
2995  unsigned int nb_bits;
2996  bool is_blue_first;
2997  bool is_shm_enabled;
2998  bool byte_order;
2999 #ifdef cimg_use_xrandr
3000  XRRScreenSize *resolutions;
3001  Rotation curr_rotation;
3002  unsigned int curr_resolution;
3003  unsigned int nb_resolutions;
3004 #endif
3005  X11_info():nb_wins(0),events_thread(0),display(0),
3006  nb_bits(0),is_blue_first(false),is_shm_enabled(false),byte_order(false) {
3007 #ifdef __FreeBSD__
3008  XInitThreads();
3009 #endif
3010  wins = new CImgDisplay*[1024];
3011  pthread_mutex_init(&wait_event_mutex,0);
3012  pthread_cond_init(&wait_event,0);
3013 #ifdef cimg_use_xrandr
3014  resolutions = 0;
3015  curr_rotation = 0;
3016  curr_resolution = nb_resolutions = 0;
3017 #endif
3018  }
3019 
3020  ~X11_info() {
3021  delete[] wins;
3022  /*
3023  if (events_thread) {
3024  pthread_cancel(*events_thread);
3025  delete events_thread;
3026  }
3027  if (display) { } // XCloseDisplay(display); }
3028  pthread_cond_destroy(&wait_event);
3029  pthread_mutex_unlock(&wait_event_mutex);
3030  pthread_mutex_destroy(&wait_event_mutex);
3031  */
3032  }
3033  };
3034 #if defined(cimg_module)
3035  X11_info& X11_attr();
3036 #elif defined(cimg_main)
3037  X11_info& X11_attr() { static X11_info val; return val; }
3038 #else
3039  inline X11_info& X11_attr() { static X11_info val; return val; }
3040 #endif
3041 #define cimg_lock_display() cimg::mutex(15)
3042 #define cimg_unlock_display() cimg::mutex(15,0)
3043 
3044 #elif cimg_display==2
3045  struct Win32_info {
3046  HANDLE wait_event;
3047  Win32_info() { wait_event = CreateEvent(0,FALSE,FALSE,0); }
3048  };
3049 #if defined(cimg_module)
3050  Win32_info& Win32_attr();
3051 #elif defined(cimg_main)
3052  Win32_info& Win32_attr() { static Win32_info val; return val; }
3053 #else
3054  inline Win32_info& Win32_attr() { static Win32_info val; return val; }
3055 #endif
3056 #endif
3057 
3058  struct Mutex_info {
3059 #if cimg_OS==2
3060  HANDLE mutex[32];
3061  Mutex_info() { for (unsigned int i = 0; i<32; ++i) mutex[i] = CreateMutex(0,FALSE,0); }
3062  void lock(const unsigned int n) { WaitForSingleObject(mutex[n],INFINITE); }
3063  void unlock(const unsigned int n) { ReleaseMutex(mutex[n]); }
3064  int trylock(const unsigned int) { return 0; }
3065 #elif defined(_PTHREAD_H)
3066  pthread_mutex_t mutex[32];
3067  Mutex_info() { for (unsigned int i = 0; i<32; ++i) pthread_mutex_init(&mutex[i],0); }
3068  void lock(const unsigned int n) { pthread_mutex_lock(&mutex[n]); }
3069  void unlock(const unsigned int n) { pthread_mutex_unlock(&mutex[n]); }
3070  int trylock(const unsigned int n) { return pthread_mutex_trylock(&mutex[n]); }
3071 #else
3072  Mutex_info() {}
3073  void lock(const unsigned int) {}
3074  void unlock(const unsigned int) {}
3075  int trylock(const unsigned int) { return 0; }
3076 #endif
3077  };
3078 #if defined(cimg_module)
3079  Mutex_info& Mutex_attr();
3080 #elif defined(cimg_main)
3081  Mutex_info& Mutex_attr() { static Mutex_info val; return val; }
3082 #else
3083  inline Mutex_info& Mutex_attr() { static Mutex_info val; return val; }
3084 #endif
3085 
3086 #if defined(cimg_use_magick)
3087  static struct Magick_info {
3088  Magick_info() {
3089  Magick::InitializeMagick("");
3090  }
3091  } _Magick_info;
3092 #endif
3093 
3094 #if cimg_display==1
3095  // Define keycodes for X11-based graphical systems.
3096  const unsigned int keyESC = XK_Escape;
3097  const unsigned int keyF1 = XK_F1;
3098  const unsigned int keyF2 = XK_F2;
3099  const unsigned int keyF3 = XK_F3;
3100  const unsigned int keyF4 = XK_F4;
3101  const unsigned int keyF5 = XK_F5;
3102  const unsigned int keyF6 = XK_F6;
3103  const unsigned int keyF7 = XK_F7;
3104  const unsigned int keyF8 = XK_F8;
3105  const unsigned int keyF9 = XK_F9;
3106  const unsigned int keyF10 = XK_F10;
3107  const unsigned int keyF11 = XK_F11;
3108  const unsigned int keyF12 = XK_F12;
3109  const unsigned int keyPAUSE = XK_Pause;
3110  const unsigned int key1 = XK_1;
3111  const unsigned int key2 = XK_2;
3112  const unsigned int key3 = XK_3;
3113  const unsigned int key4 = XK_4;
3114  const unsigned int key5 = XK_5;
3115  const unsigned int key6 = XK_6;
3116  const unsigned int key7 = XK_7;
3117  const unsigned int key8 = XK_8;
3118  const unsigned int key9 = XK_9;
3119  const unsigned int key0 = XK_0;
3120  const unsigned int keyBACKSPACE = XK_BackSpace;
3121  const unsigned int keyINSERT = XK_Insert;
3122  const unsigned int keyHOME = XK_Home;
3123  const unsigned int keyPAGEUP = XK_Page_Up;
3124  const unsigned int keyTAB = XK_Tab;
3125  const unsigned int keyQ = XK_q;
3126  const unsigned int keyW = XK_w;
3127  const unsigned int keyE = XK_e;
3128  const unsigned int keyR = XK_r;
3129  const unsigned int keyT = XK_t;
3130  const unsigned int keyY = XK_y;
3131  const unsigned int keyU = XK_u;
3132  const unsigned int keyI = XK_i;
3133  const unsigned int keyO = XK_o;
3134  const unsigned int keyP = XK_p;
3135  const unsigned int keyDELETE = XK_Delete;
3136  const unsigned int keyEND = XK_End;
3137  const unsigned int keyPAGEDOWN = XK_Page_Down;
3138  const unsigned int keyCAPSLOCK = XK_Caps_Lock;
3139  const unsigned int keyA = XK_a;
3140  const unsigned int keyS = XK_s;
3141  const unsigned int keyD = XK_d;
3142  const unsigned int keyF = XK_f;
3143  const unsigned int keyG = XK_g;
3144  const unsigned int keyH = XK_h;
3145  const unsigned int keyJ = XK_j;
3146  const unsigned int keyK = XK_k;
3147  const unsigned int keyL = XK_l;
3148  const unsigned int keyENTER = XK_Return;
3149  const unsigned int keySHIFTLEFT = XK_Shift_L;
3150  const unsigned int keyZ = XK_z;
3151  const unsigned int keyX = XK_x;
3152  const unsigned int keyC = XK_c;
3153  const unsigned int keyV = XK_v;
3154  const unsigned int keyB = XK_b;
3155  const unsigned int keyN = XK_n;
3156  const unsigned int keyM = XK_m;
3157  const unsigned int keySHIFTRIGHT = XK_Shift_R;
3158  const unsigned int keyARROWUP = XK_Up;
3159  const unsigned int keyCTRLLEFT = XK_Control_L;
3160  const unsigned int keyAPPLEFT = XK_Super_L;
3161  const unsigned int keyALT = XK_Alt_L;
3162  const unsigned int keySPACE = XK_space;
3163  const unsigned int keyALTGR = XK_Alt_R;
3164  const unsigned int keyAPPRIGHT = XK_Super_R;
3165  const unsigned int keyMENU = XK_Menu;
3166  const unsigned int keyCTRLRIGHT = XK_Control_R;
3167  const unsigned int keyARROWLEFT = XK_Left;
3168  const unsigned int keyARROWDOWN = XK_Down;
3169  const unsigned int keyARROWRIGHT = XK_Right;
3170  const unsigned int keyPAD0 = XK_KP_0;
3171  const unsigned int keyPAD1 = XK_KP_1;
3172  const unsigned int keyPAD2 = XK_KP_2;
3173  const unsigned int keyPAD3 = XK_KP_3;
3174  const unsigned int keyPAD4 = XK_KP_4;
3175  const unsigned int keyPAD5 = XK_KP_5;
3176  const unsigned int keyPAD6 = XK_KP_6;
3177  const unsigned int keyPAD7 = XK_KP_7;
3178  const unsigned int keyPAD8 = XK_KP_8;
3179  const unsigned int keyPAD9 = XK_KP_9;
3180  const unsigned int keyPADADD = XK_KP_Add;
3181  const unsigned int keyPADSUB = XK_KP_Subtract;
3182  const unsigned int keyPADMUL = XK_KP_Multiply;
3183  const unsigned int keyPADDIV = XK_KP_Divide;
3184 
3185 #elif cimg_display==2
3186  // Define keycodes for Windows.
3187  const unsigned int keyESC = VK_ESCAPE;
3188  const unsigned int keyF1 = VK_F1;
3189  const unsigned int keyF2 = VK_F2;
3190  const unsigned int keyF3 = VK_F3;
3191  const unsigned int keyF4 = VK_F4;
3192  const unsigned int keyF5 = VK_F5;
3193  const unsigned int keyF6 = VK_F6;
3194  const unsigned int keyF7 = VK_F7;
3195  const unsigned int keyF8 = VK_F8;
3196  const unsigned int keyF9 = VK_F9;
3197  const unsigned int keyF10 = VK_F10;
3198  const unsigned int keyF11 = VK_F11;
3199  const unsigned int keyF12 = VK_F12;
3200  const unsigned int keyPAUSE = VK_PAUSE;
3201  const unsigned int key1 = '1';
3202  const unsigned int key2 = '2';
3203  const unsigned int key3 = '3';
3204  const unsigned int key4 = '4';
3205  const unsigned int key5 = '5';
3206  const unsigned int key6 = '6';
3207  const unsigned int key7 = '7';
3208  const unsigned int key8 = '8';
3209  const unsigned int key9 = '9';
3210  const unsigned int key0 = '0';
3211  const unsigned int keyBACKSPACE = VK_BACK;
3212  const unsigned int keyINSERT = VK_INSERT;
3213  const unsigned int keyHOME = VK_HOME;
3214  const unsigned int keyPAGEUP = VK_PRIOR;
3215  const unsigned int keyTAB = VK_TAB;
3216  const unsigned int keyQ = 'Q';
3217  const unsigned int keyW = 'W';
3218  const unsigned int keyE = 'E';
3219  const unsigned int keyR = 'R';
3220  const unsigned int keyT = 'T';
3221  const unsigned int keyY = 'Y';
3222  const unsigned int keyU = 'U';
3223  const unsigned int keyI = 'I';
3224  const unsigned int keyO = 'O';
3225  const unsigned int keyP = 'P';
3226  const unsigned int keyDELETE = VK_DELETE;
3227  const unsigned int keyEND = VK_END;
3228  const unsigned int keyPAGEDOWN = VK_NEXT;
3229  const unsigned int keyCAPSLOCK = VK_CAPITAL;
3230  const unsigned int keyA = 'A';
3231  const unsigned int keyS = 'S';
3232  const unsigned int keyD = 'D';
3233  const unsigned int keyF = 'F';
3234  const unsigned int keyG = 'G';
3235  const unsigned int keyH = 'H';
3236  const unsigned int keyJ = 'J';
3237  const unsigned int keyK = 'K';
3238  const unsigned int keyL = 'L';
3239  const unsigned int keyENTER = VK_RETURN;
3240  const unsigned int keySHIFTLEFT = VK_SHIFT;
3241  const unsigned int keyZ = 'Z';
3242  const unsigned int keyX = 'X';
3243  const unsigned int keyC = 'C';
3244  const unsigned int keyV = 'V';
3245  const unsigned int keyB = 'B';
3246  const unsigned int keyN = 'N';
3247  const unsigned int keyM = 'M';
3248  const unsigned int keySHIFTRIGHT = VK_SHIFT;
3249  const unsigned int keyARROWUP = VK_UP;
3250  const unsigned int keyCTRLLEFT = VK_CONTROL;
3251  const unsigned int keyAPPLEFT = VK_LWIN;
3252  const unsigned int keyALT = VK_LMENU;
3253  const unsigned int keySPACE = VK_SPACE;
3254  const unsigned int keyALTGR = VK_CONTROL;
3255  const unsigned int keyAPPRIGHT = VK_RWIN;
3256  const unsigned int keyMENU = VK_APPS;
3257  const unsigned int keyCTRLRIGHT = VK_CONTROL;
3258  const unsigned int keyARROWLEFT = VK_LEFT;
3259  const unsigned int keyARROWDOWN = VK_DOWN;
3260  const unsigned int keyARROWRIGHT = VK_RIGHT;
3261  const unsigned int keyPAD0 = 0x60;
3262  const unsigned int keyPAD1 = 0x61;
3263  const unsigned int keyPAD2 = 0x62;
3264  const unsigned int keyPAD3 = 0x63;
3265  const unsigned int keyPAD4 = 0x64;
3266  const unsigned int keyPAD5 = 0x65;
3267  const unsigned int keyPAD6 = 0x66;
3268  const unsigned int keyPAD7 = 0x67;
3269  const unsigned int keyPAD8 = 0x68;
3270  const unsigned int keyPAD9 = 0x69;
3271  const unsigned int keyPADADD = VK_ADD;
3272  const unsigned int keyPADSUB = VK_SUBTRACT;
3273  const unsigned int keyPADMUL = VK_MULTIPLY;
3274  const unsigned int keyPADDIV = VK_DIVIDE;
3275 
3276 #else
3277  // Define random keycodes when no display is available.
3278  // (should rarely be used then!).
3279  const unsigned int keyESC = 1U;
3280  const unsigned int keyF1 = 2U;
3281  const unsigned int keyF2 = 3U;
3282  const unsigned int keyF3 = 4U;
3283  const unsigned int keyF4 = 5U;
3284  const unsigned int keyF5 = 6U;
3285  const unsigned int keyF6 = 7U;
3286  const unsigned int keyF7 = 8U;
3287  const unsigned int keyF8 = 9U;
3288  const unsigned int keyF9 = 10U;
3289  const unsigned int keyF10 = 11U;
3290  const unsigned int keyF11 = 12U;
3291  const unsigned int keyF12 = 13U;
3292  const unsigned int keyPAUSE = 14U;
3293  const unsigned int key1 = 15U;
3294  const unsigned int key2 = 16U;
3295  const unsigned int key3 = 17U;
3296  const unsigned int key4 = 18U;
3297  const unsigned int key5 = 19U;
3298  const unsigned int key6 = 20U;
3299  const unsigned int key7 = 21U;
3300  const unsigned int key8 = 22U;
3301  const unsigned int key9 = 23U;
3302  const unsigned int key0 = 24U;
3303  const unsigned int keyBACKSPACE = 25U;
3304  const unsigned int keyINSERT = 26U;
3305  const unsigned int keyHOME = 27U;
3306  const unsigned int keyPAGEUP = 28U;
3307  const unsigned int keyTAB = 29U;
3308  const unsigned int keyQ = 30U;
3309  const unsigned int keyW = 31U;
3310  const unsigned int keyE = 32U;
3311  const unsigned int keyR = 33U;
3312  const unsigned int keyT = 34U;
3313  const unsigned int keyY = 35U;
3314  const unsigned int keyU = 36U;
3315  const unsigned int keyI = 37U;
3316  const unsigned int keyO = 38U;
3317  const unsigned int keyP = 39U;
3318  const unsigned int keyDELETE = 40U;
3319  const unsigned int keyEND = 41U;
3320  const unsigned int keyPAGEDOWN = 42U;
3321  const unsigned int keyCAPSLOCK = 43U;
3322  const unsigned int keyA = 44U;
3323  const unsigned int keyS = 45U;
3324  const unsigned int keyD = 46U;
3325  const unsigned int keyF = 47U;
3326  const unsigned int keyG = 48U;
3327  const unsigned int keyH = 49U;
3328  const unsigned int keyJ = 50U;
3329  const unsigned int keyK = 51U;
3330  const unsigned int keyL = 52U;
3331  const unsigned int keyENTER = 53U;
3332  const unsigned int keySHIFTLEFT = 54U;
3333  const unsigned int keyZ = 55U;
3334  const unsigned int keyX = 56U;
3335  const unsigned int keyC = 57U;
3336  const unsigned int keyV = 58U;
3337  const unsigned int keyB = 59U;
3338  const unsigned int keyN = 60U;
3339  const unsigned int keyM = 61U;
3340  const unsigned int keySHIFTRIGHT = 62U;
3341  const unsigned int keyARROWUP = 63U;
3342  const unsigned int keyCTRLLEFT = 64U;
3343  const unsigned int keyAPPLEFT = 65U;
3344  const unsigned int keyALT = 66U;
3345  const unsigned int keySPACE = 67U;
3346  const unsigned int keyALTGR = 68U;
3347  const unsigned int keyAPPRIGHT = 69U;
3348  const unsigned int keyMENU = 70U;
3349  const unsigned int keyCTRLRIGHT = 71U;
3350  const unsigned int keyARROWLEFT = 72U;
3351  const unsigned int keyARROWDOWN = 73U;
3352  const unsigned int keyARROWRIGHT = 74U;
3353  const unsigned int keyPAD0 = 75U;
3354  const unsigned int keyPAD1 = 76U;
3355  const unsigned int keyPAD2 = 77U;
3356  const unsigned int keyPAD3 = 78U;
3357  const unsigned int keyPAD4 = 79U;
3358  const unsigned int keyPAD5 = 80U;
3359  const unsigned int keyPAD6 = 81U;
3360  const unsigned int keyPAD7 = 82U;
3361  const unsigned int keyPAD8 = 83U;
3362  const unsigned int keyPAD9 = 84U;
3363  const unsigned int keyPADADD = 85U;
3364  const unsigned int keyPADSUB = 86U;
3365  const unsigned int keyPADMUL = 87U;
3366  const unsigned int keyPADDIV = 88U;
3367 #endif
3368 
3369  const double PI = 3.14159265358979323846;
3370 
3371  // Define a 12x13 font (small size).
3372  static const char *const data_font12x13 =
3373  " .wjwlwmyuw>wjwkwbwjwkwRxuwmwjwkwmyuwJwjwlx`w Fw "
3374  " mwlwlwuwnwuynwuwmyTwlwkwuwmwuwnwlwkwuwmwuw_wuxlwlwkwuwnwuynwuwTwlwlwtwnwtwnw my Qw +wlw b"
3375  "{ \\w Wx`xTw_w[wbxawSwkw nynwky<x1w `y ,w Xwuw CxlwiwlwmyuwbwuwUwiwlwbwiwrwqw^wuwmxuwnwiwlwmy"
3376  "uwJwiwlw^wnwEymymymymy1w^wkxnxtxnw<| gybwkwuwjwtwowmxswnxnwkxlxkw:wlymxlymykwn{myo{nymy2ykwqwqwm{myo"
3377  "zn{o{mzpwrwpwkwkwswowkwqwqxswnyozlyozmzp}pwrwqwqwqwswswsxsxqwqwp}qwlwiwjybw`w[wcw_wkwkwkwkw mw\"wlwiw"
3378  "=wtw`xIw awuwlwm{o{mylwn|pwtwtwoy`w_w_wbwiwkxcwqwpwkznwuwjzpyGzqymyaxlylw_zWxkxaxrwqxrwqyswowkwkwkwk"
3379  "wkwkwk}qyo{o{o{o{owkwkwkwkznxswnymymymymyayuwqwrwpwrwpwrwpwrwqwqwpwkwtwlwkwlwuwnwuynwuwmyTwkwlwuwmwu"
3380  "wnwkwlwuwmwuwkxlwuxmwkwlwuwnwuynwuwTwkwlwuwmwuwlwmwkwtwUwuwuwowswowswowswowsw;wqwtw_ymzp~py>w bwswcw"
3381  "kwuwjwuwozpwtwuwnwtwowkwjwmwuwuwkwIxmxuxowuwmwswowswmxnwjwhwowswowsw0wmwowswuwnwrwowswpwswowkwjwrwqw"
3382  "rwpwkwkwtwnwkxsxqxswowswpwswnwswpwswowrwnwmwrwqwqwqwswswrwswowswjwpwlxjwkxuxLw[wcw_wSwkw mw\"wlwiw=wt"
3383  "wmxlwFw cwswnwuwnwkwjwswo{pwrwpwtwtwpwswby`w`yUwlwtwpwqwpwswowlw\\wrwrxuwHwrwfwuwjwlwlwTyuwVwlwtwawsw"
3384  "owswowswcwuwmwuwmwuwmwuwmwuwlwkwuwnwswpwkwkwkwkwkwkwkwkwswoxswowswowswowswowswowswowrwpwswpwrwpwrwpw"
3385  "rwpwrwpwswoznwtw Ww (wGwtwtwqwqwqwuwuwuwqwswuwqwqw=wqxtw`{nzp~q{ozowrwnxmwtwow bzawkwuwl}rwuwnwtwuw"
3386  "nwtwowkwjwlyjwIwlwswmwiwkwnwuwnwkwhwnwswowswowkwewewixnwsytwswuwnwrwpwkwrwpwkwkwkwrwpwkwkwuwmwkxsxqw"
3387  "uwtwpwqwqwswowqwqwswowiwmwrwpwswowtwtwpwuwmwuwjwowkwjwlxsxXynzmymznyozlzoznwkwkwtwnwkzuyrzmynzmzowux"
3388  "myozmwswpwrwowtwtwrwrwpwrwp{mwlwiwHyuwpwtwkwmxlynzoxswmwmwswnwswowtxq|owtwtwpym{p{owswnwuwmwlwkwqwqx"
3389  "uwuxqwrwpwtwtwqwqwowlwuwuwkwmwlwtwowuwuwdwjznwl{nwuwnwkx_wtxtwswtwlwtwWwuytwgyjwmwjwawswoyuwVwlwtwnw"
3390  "twmwtwnwtwmwuwmwlwuwmwuwmwuwmwuwmwuwmwuwmxuwowkwkwkwkwkwkwkwkwkwrwpwuwtwpwqwqwqwqwqwqwqwqwqwowtwpwsw"
3391  "uwqwrwpwrwpwrwpwrwowuwnwswowuwlymymymymymymyuyqymymymymynwkwkwkwjynzmymymymymykwmzowswowswowswowswpw"
3392  "rwozowrwW}q}qwtwtwqwtwtwqwtwtwA}rwuw_{p~r~r}pwtwowrwnxmwtwow aw_w]wtwpwuwmxuwmybwjwlyjwIwlwswmwiwnyn"
3393  "wtwnznzkwmynwswTyp}pylwmwtwtwtwswuwn{owkwrwp{o{owk|pwkwkxlwkwuwuwuwqwuwtwpwqwqwswowqwqwswoykwmwrwpws"
3394  "wowuwuwuwowkwjwnwkwjwDwowswowkwswowswowkwswowswowkwkwuwmwkwswswswswowswowswowswoxlwswowkwswpwrwowtwt"
3395  "wqwtwowrwlwoxkwhxVxuxpwtypwuwjwnwtwnwkwswowtxnxmwswowqwqwtwuxqwtwnwtwtwqwswowswmwm{nwuwlxnwkwqwqwtwt"
3396  "wqwrwpwtwtwqwuyuwpwiwhwnwmwrwnwbwkwuwlwlwswoxuxowlwtw`wuwrwszmwtwo}dwuwtwuw[}qymx`wswoyuwow_ylxlwtwo"
3397  "yuwoyuwoyuwmwlwuwmwuwmwuwmwuwmwuwmwuwmwt{swk{o{o{o{owkwkwkwlztwpwuwtwpwqwqwqwqwqwqwqwqwqwnxowtwtwqwr"
3398  "wpwrwpwrwpwrwnwmwswowuwiwkwkwkwkwkwkwswswkwswowswowswowswowkwkwkwkwswowswowswowswowswowswowswcwtxows"
3399  "wowswowswowswpwrwowswpwrwWwtwtwqwqwqwuwuwuwqwuwswqwqw>wowuw`}q~q|q}qwrwpwrwowtwnwtwo~ izaw]wtwoykwux"
3400  "qwtwswfwjwmwuwuwn}eyaxlwswmwjwjwpwswjwowswmwmwswnzWy]ypwlwtwtwuwswswowrwpwkwrwpwkwkwsyqwrwpwkwkwuwmw"
3401  "kwuwuwuwqwtwuwpwqwqznwqwqzkynwmwrwowuwnwuwuwuwowkwjwnwkxkwGzowswowkwswo{owkwswowswowkwkxlwkwswswswsw"
3402  "owswowswowswowjxmwkwswowtwnwuwuwuwpxmwtwlwlwlwiwlytwewtwtwqwswowtxoznwswnxmwswnwuwmwuwnwswowtwtwqwtw"
3403  "twqwtwnwtwtwqwswowswmwmwswowswmwmwkwqwqwtwtwqwrwowuwuwpwuyuwq~own~own~owbwkwuwmznwswmwbwswawuwrwgwtw"
3404  "hwdwuytwXwJwswnxuw=wtwmwswowtxowswqxmwswowswowswowswowswowswnwtwowkwkwkwkwkwkwkwkwkwrwpwtwuwpwqwqwqw"
3405  "qwqwqwqwqwqwnxowtwtwqwrwpwrwpwrwpwrwnwmwswowtwmznznznznznzn~swk{o{o{o{owkwkwkwkwswowswowswowswowswow"
3406  "swowswo}qwuwuwowswowswowswowswowtwnwswowtwUwuwuwowswowswowswowsw@}qx`}q~pzo{pwrwpwrwowtwnwtwow aw_w_"
3407  "}owuwmwuwtwrwswuwewjwkwiwJwkwswmwkwiwp|kwowswmwmwswkwWym}mypwlwszr{owrwpwkwrwpwkwkwqwqwrwpwkwkwtwnwk"
3408  "wtwtwqwtwuwpwqwqwkwqwqwtwiwnwmwrwowuwnwuwuwuwpwuwlwkwmwjwkwHwswowswowkwswowkwkwswowswowkwkwuwmwkwsws"
3409  "wswswowswowswowswowhwnwkwswowtwnwuwuwuwpxmwtwmwkwlwiwmwtydwtwtwqwswowswowtwnwswowkwswnwuwnwtwnwswowt"
3410  "wtwqwtwtwqwtwnwtwtwqwswowswmwmwswowswnwlwkwqwqxuwuxqwrwnyowqwpwiwhwpwuwuwowrwpwuwuwdwkwuwlwlwswo{owk"
3411  "xuwawtxtwszmwtwiwdwuwtwuwXwJwswmwuwKzmwtwlwtxowrwpwtxrxl{o{o{o{o{o{o{owkwkwkwkwkwkwkwkwkwrwpwtwuwpwq"
3412  "wqwqwqwqwqwqwqwqwowtwpwuwswqwrwpwrwpwrwpwrwnwmznwswowswowswowswowswowswowswowswowkwkwkwkwkwkwkwkwkws"
3413  "wowswowswowswowswowswowswcwuwuwowswowswowswowswowtwnwswowtwTymymymymy=wmw^wuwuwmxlxmyowrwowtwnwtwmxm"
3414  "w bwswIwuwmwuwmwuwtwrxswdwjw]wJwkxuxmwlwlwswlwjwowswmwmwswlwSycyawlwswowrwowswpwswowkwjwrwqwrwpwkwkw"
3415  "swowkwqwqwsxowswpwjwswpwswowrwnwmxtxnwlwswpwswmwlwlwjwkwHwswowswowkwswowswowkwswowswowkwkwtwnwkwswsw"
3416  "swswowswowswowswowkwswowkwswnxlwswpwtwmxmwjwlwiwTxuxpwtxowswowtwnwswowkwswnynwtwnwswowtwtwqxuwuxqwtw"
3417  "nwtwtwqwswowswmwlwuwnwswowkwjwswo{pwrwmwmwswnwjwiwnymwtwnycwkwuwlwl{mwmwiw_wrwdwtwVwrw*wswmwuw?wtwlw"
3418  "tzqwrwpwtzswkwswowswowswowswowswowswowswnwswpwkwkwkwkwkwkwkwkwswowsxowswowswowswowswowswowrwpwswpxtx"
3419  "pxtxpxtxpxtxnwmwkwswowswowswowswowswowswowswowtxowkwswowswowswowswowkwkwkwkwswowswowswowswowswowswow"
3420  "swlwnxtwowswowswowswowswnxmwswnx >wlw\\wkx`wnwrwoznwtwmxl| gybw^wtwozmwsxpzuxfxlx]wnw_wlxjyn{o{nykwnz"
3421  "mymwkynymwkwewewjwjwrwswqwp{myozn{owizpwrwpwkwkwrwp{owqwqwsxnyowiyowrwozmwlzmwlwswqxsxnwm}qwjxlwGzoz"
3422  "mymznynwjzowswowkwkwswowkwswswswswnynzmzowjymxlznxlwswqwrwnwm{mwlwiwHxuxpzmxlymynwswmwnwrwozmxuxo{pw"
3423  "txn{pzmykwmyo}p{owkyuynwnwrwmwly`w_w_wbwjzo{pwqwnwmwhw_z>zY}M|nwuw2wqwqwryrwqwqyowqwqwqwqwqwqwqwqwqw"
3424  "qwqwqwr{qyo{o{o{o{owkwkwkwkznwsxnymymymymycwuynznznznzmwmwkwuynznznznznznznyuzrymymymymynwkwkwkwjynw"
3425  "swnymymymymybzmznznznznwlzmw hwHwlwSwTw <w8z ]x tx Zxjwmx RwWw/wgw pw_ynwky=wCwmwaw\\w_wnw 1wIwl"
3426  "z 'wiwuwaw mw Pw swlwjw hw f| pyWx/wgw rxSw/wCwmwaw\\w_wnw 1w AwRx nw Pw txk"
3427  "wlxm";
3428 
3429  // Define a 20x23 font (normal size).
3430  static const char *const data_font20x23 =
3431  " 9q\\q^r_rnp`qnq`plp7q\\q^q_qmqbq\\q^q_qmqHqmp_q\\q^r_rnp"
3432  "`qnq7q\\q^q_qmq_q \"r Mq^q^qnq`pnr`qnq`plp6q^q^p"
3433  "mp`qmqaq^q^pmp`qmqIpmq]q^q^qnq`pnr`qnq6q^q^pmp`qmq`q \"plp 'q 5qmq Vq "
3434  " Xq [plp 3qYq_p^rnpLplp8qYq_qNqYq_q4rmpaqYq_q_rmp%qYq^pGq Irc|!pKp]raqjq`p "
3435  "HtNq_qmq\\plqbp_shpdscq[q^q[p [q]s_r`uau]rbv`tcxbuat LsZucrav_udwcxdw`udqiqeq]q]qjreq]sksgrjqbtcv_tcv"
3436  "aud{eqiqgqfqgqjsjqlrjrhrirfzfs`q[sZqMqJqCqNsLq]q]q]q]q .scq]s \\sKt%r [s^raxdxat_qazgqlqlqctJqIqIq"
3437  "LqHsOqiqOtaqmq\\uft nufu`sLs`t\\qKv<r\\rLrepirepitgpeq]r^r^r^r^r^r^{gudxdxdxdxdq]q]q]q]wcrjqbt`t`t`t`tL"
3438  "tlpgqiqeqiqeqiqeqiqgrireq[s_q[q_pnp_pnr`qnq`plp7q[q_s`qmqcq[q_s`qmq]pkpbpmr`q[q_s`pmraqmq8q[q^pnp_qn"
3439  "q^qaq\\qnq !pnqd{!pJp^tdunucr _y dvOq_qmq\\plpap_pmpipdudq[p\\p_plplp _q^ubtawcw^rbvavdxcwcw Ou]yerawb"
3440  "xeyexdwbxeqiqeq]q]qkrdq]sksgrjqdxewbxewcwe{eqiqfqhqfqjsjqkqjqfqiqezfs`q[s[sMpJqCqOtLq]q]q]q]q q 1tc"
3441  "q]t ^vaq_w&r \\u_raxdxcxcuczgqlqlqexMsJqJsMq[p^uPqiqdq]uaqmq]qkqcq!qkqguaqmqNpkp\\p]pKtmp:p]plpKpfpfp"
3442  "fpcpipdq]r^r^r^r^r^r^{ixexdxdxdxdq]q]q]q]yerjqdxdxdxdxdxPwnpfqiqeqiqeqiqeqiqfqiqdq\\u_p[p^pnpKqnq_r5p"
3443  "[p^pmp`qmqbp[p^pmp`qmq]tKp[p^pmpLqmq7p[p]pnp_qnq^p`q\\qnq5uauauauaucq`qhq4p]pKr_ueunucr `q \\rkpOq_qm"
3444  "q\\plpctbqmqkqerlpdq\\q\\q_qnpnq\\q%q^qkqcqnqapjrdpjr`sbq]rkp^qcrkrerkq Oplr`sirgtbqkrdripeqjsfq]q]ripeq"
3445  "iqeq]q]qlrcq]sksgskqerjrfqkrdrjrfqkrerjp`q`qiqfqhqeqkskqiqlqdqkq\\qeq]qZq\\qmqNqKqCqOqIq5q]q q 1q`qZq"
3446  " _rlqbtaqjp$q ^qkqatbr^q]rjrewdqhqgqlqlqfrjrOuKqKu8p_rlpOqkqcq]qFpgpcp\"pgpTpkp\\q^p\\p^qLump:p^pjpLpg"
3447  "pepgpbpjpPt`t`t`t`t`qnq_qnqcripeq]q]q]q]q]q]q]q]qjsfskqerjrfrjrfrjrfrjrfrjrRrjrfqiqeqiqeqiqeqiqeqkqc"
3448  "vbrlq`q]q_plp Iq]q_qmqNq]q_qmqKtIq]q_qmq ^q]q^plpKq`q mqkqcqkqcqkqcqkqcqkqdq`qhq5q^qLt`ueunudtasbqip"
3449  "`q`pipcq [qIq_qmq`{gvcqmqkpdq_q\\q\\q]rZq%q_rkraqZq]qaqnqbq]qXqcqiqeqiq1pSpXq`qfrhqnqbqjqdq]qhqfq]q]q"
3450  "]qiqeq]q]qmrbq]qnqmqnqgskqeqhqfqjqdqhqfqjqeqYq`qiqfrjreqkskqirnrdrmr]qdq]qZq]qkq)qCqOqIq5q]q q 1q`q"
3451  "Zq _qkq_qaq mq ^qkqaqnqar_q]qhqfrnqnreqhqgqlqlqfqhqPwLqLw9p_q_phqdqkqcq]qGplslpiu#pmtlpUpkp\\q_q_r8u"
3452  "mp:p^pjpLpgpepgperipcq^qnq`qnq`qnq`qnq`qnq`qnq`qmqcq]q]q]q]q]q]q]q]q]qhqfskqeqhqfqhqfqhqfqhqfqhqdphp"
3453  "fqirfqiqeqiqeqiqeqiqermrcwcqkq [q 3qZp Oq nqmqmqeqiqeqiqeqiqeqiqeq_piq4q^pLvatd|evdvcqipasaqkqdq "
3454  " [qHq_qmq`{hrnpmpcqmqlpcq_q\\pZp]rZq%q_qiqaqZq]qapmqbq^qWqcqiqeqiqdq]qUsSs[qaqdqhqnqbqjqeq\\qgqgq]q^q\\"
3455  "qiqeq]q]qnraq]qnqmqnqgqnqlqfqfqgqjqeqfqgqjqeqYq`qiqeqjqdqlqmqlqhqnqbqmq]rdq]qZq^pgp=taqns`s`snqatdv_"
3456  "snqcqnsbq]q]qkqcq]qnsmshqns`saqnsasnqcqnr`tbvaqjqeqiqdqkqkqjrkreqiqdw`q`qZq#tnreqkq^qatauaqnsdqiq`ra"
3457  "qjqdqiqdpmrcxdqmqmqatbxfyeqiqbqnq`r`q^qfqhrmqmrfqhqgqlqlqgqfqep[pnqnp[p`q`pipbpnqnpNq]taq^qnqnqbqmqb"
3458  "q\\qIqmpkpmqkqkp$qmpkpmqVqmq\\q`q[pLqjqeump:p^pjpLphpdphpapkpbq^qnq`qnq`qnq`qnq`qnq`qnq`qmqdq\\q]q]q]q]"
3459  "q]q]q]q]qgqgqnqlqfqfqhqfqhqfqhqfqhqfqfrjrhqiqnqgqiqeqiqeqiqeqiqdqmqbqkrdqmsbt`t`t`t`t`t`tlsfs_t`t`t`"
3460  "tbq]q]q]q[tbqns`s_s_s_s_s\\q`smpdqjqdqjqdqjqdqjqeqiqdqnscqiq;qlqlqgqgqgqnqmqnqgqjqnqgqgqfq_qjq<{fpjpL"
3461  "vatd|fxeqkqdqipasaqkqdp \\yNqGplqeqmp`qmqmqcrLqZq`qnpnq\\q%q_qiqaqZq^rbqmqbubqms^qaqkqdqiqdq]qXuf{fu_"
3462  "q`qlrnqlqjqlqcqkreq\\qgqgq]q^q\\qiqeq]q]t`q]qnqmqnqgqnqlqfqfqgqkreqfqgqkres[q`qiqeqjqdqlqmqlqhs`s]rcq]"
3463  "qZq#vbwcvbwcwev`wcwcq]q]qlqbq]vnthwcwcwcwcubwcvaqjqdqkqcqkqkqiqkqdqiqdw`q`qZq7smsfxdqlr^qavdvawdqkq_"
3464  "raqjqdpgpeqntdxdqmqmqcwdyfyeqiqcqlq`raq^qfqhqlqlqfqhqgqlqlqgqfqfrZqZraqarkraqLq^vbq^wbqmqbq]tKpmpfpk"
3465  "pjp_plp9plpkplpUs[qaqZpLqjqeump:p^pjpaplp_piqdpiqaplqbq_qlqbqlqbqlqbqlqbqlqbqlqbrmqdq\\q]q]q]q]q]q]q]"
3466  "q]qgqgqnqlqfqfqhqfqhqfqhqfqhqfqerlrgqjqmqgqiqeqiqeqiqeqiqcsaqjqdqnq`vbvbvbvbvbvbvnuivbwcwcwcwcq]q]q]"
3467  "q]wcwcwcwcwcwcwOwcqjqdqjqdqjqdqjqeqiqdwdqiq;pkqkpgpepgpmumpgpjrmpgpepfq_qkq;{hrkpLxdxf|fxepipdqipas`"
3468  "pkpcp ZqHqGplpdt_pmplpmshsMqZqaplplp]q&q^qiqaq[qat`plqbvcx_q`ucrkr:uc{cucq`qlvlqjqlqcwdq\\qgqgxdvcqj"
3469  "tfyeq]q]s_q]qmsmqgqmqmqfqfqgwdqfqgwcv_q`qiqdqlqbqmqmqmqfr`s]qbq\\q[q#pjqcrlrdqkpcrlrcqkrdq^rlrcrlrdq]"
3470  "q]qmqaq]rlrlqirlrdqkqcrlrerlrcr_qjpbq]qjqdqkqcqlslqhqmqbqkq^q_q`qZq_tjpSqmsmpgrlsdqnsaqmqbqkqdq\\rlrd"
3471  "qlq_raqjqeqgqgrnqnrdqlqcqmqmqcqkqerkq`qaycqlq_rbq^qfqhqlqlqfqhqgqlqlqgqnvnqgrYqYrbqbrirbqLq_rnpmpdwa"
3472  "qmqcydq^qlqLpmpfpkpkq`plpa{RpltkpB{gpXpLqjqdtmpcqHp]plp_plp`pipjpipipmsfplpjphr_qlqbqlqbqlqbqlqbqlqb"
3473  "qlqbqlxkq\\xdxdxdxdq]q]q]q_vjqgqmqmqfqfqhqfqhqfqhqfqhqfqdrnrfqkqlqgqiqeqiqeqiqeqiqcsaqjqdqnq`pjqcpjqc"
3474  "pjqcpjqcpjqcpjqcpjrlrjqkpbqkrdqkrdqkrdqkrdq]q]q]q]qkrdrlrdqkqcqkqcqkqcqkqcqkqOqkqcqjqdqjqdqjqdqjqdqk"
3475  "qcrlrdqkq:pnwnpgpnwnpgplslpgpkrlpgpkqkpfq^qlq6qaqlpMzfzfzfzgqipdqipbqmp`qmqc| fqHqHqlpcuasmplpmpiul"
3476  "qSqZq]p^{+q^qiqaq\\q`ubqlqbpkrdrkrarawcx<tEteq`qlqlqlqjqlqcwdq\\qgqgxdvcqjtfyeq]q]t`q]qmsmqgqmqmqfqfqg"
3477  "vcqfqgv_t`q`qiqdqlqbqmqmqmqgs_q]qaq\\q[q\"vcqjqeq]qjqdqiqdq^qjqcqjqdq]q]qnq`q]qkqkqiqjqeqiqdqjqeqjqcq^"
3478  "s^q]qjqdqkqbqmsmqgqmqbqkq_qas_qYsc{Spkqkphqkrcqntcvcqiqeq\\qjqdqmr`tbqjqeqgqgqmqmqdqlqcqmqmqdqiqfqiqa"
3479  "qaycqlq_qaq^qfqhqlqlqfqhqfqmqmqfqnvnqh}cqc}cqc}cqLq_qmpawbqkqasaq^qkqMpmpfpjsnpaplp`{RplpmqkpB{huatK"
3480  "qjqbrmpcqJt^r]plpctlpjqktlpmpkpltlpjqhq^qlqbqlqbqlqbqlqbqlqcrlrcqlxkq\\xdxdxdxdq]q]q]q_vjqgqmqmqfqfqh"
3481  "qfqhqfqhqfqhqfqcteqlqkqgqiqeqiqeqiqeqiqbq`qkrdqmravbvbvbvbvbvbvjqkq]qiqeqiqeqiqeqiqdq]q]q]q^qiqdqjqe"
3482  "qiqeqiqeqiqeqiqeqiqd{hqkpnqdqjqdqjqdqjqdqjqdqkqcqjqdqkq:pnwnpgpnwnpgplslpgplrkpgpkqkpfq^qlq6qaqmqMzg"
3483  "|fxdxfqipdqipbqmqaqmqcp \\wLqK{dt]qmqmqkrmrnrSqZqK{TtKq^qiqaq]r\\rdqkq\\qdqiqaqarkrcsmq<tEtfq_qlqlqlqk"
3484  "qjqdqjqeq\\qgqgq]q^qgqfqiqeq]q]qnraq]qmsmqgqlqnqfqfqgq^qfqgqkq]raq`qiqdqlqbqnqkqnqgt`q^raq\\q[q#wcqjqe"
3485  "q]qjqdydq^qjqcqjqdq]q]s_q]qkqkqiqjqeqiqdqjqeqjqcq]uaq]qjqcqmqaqmpmpmqfs`qmq_ras_qYscpjtRpkqkphqkrcqk"
3486  "reqlrcqiqcr_qjqdqmq_qnqbqjqeqlqlqgqmqmqdqlqcqmqmqdqiqfqiqaqaqiqdqjqaq`q^qfqhqlqlqfqhqfrnqnrfqfqh}cqc"
3487  "}cqc}cqLq_qmp_q^qkq`qMrlqMpmpfpWplpUqRplplqlp=q&qjq`pmp _plp]qkpnpdqhpeqkpnpiq^qjqdqjqdqjqdqjqdqjqdq"
3488  "jqdqkqdq\\q]q]q]q]q]q]q]q]qgqgqlqnqfqfqhqfqhqfqhqfqhqfqbrdqmqjqgqiqeqiqeqiqeqiqbq`wcqlrcwcwcwcwcwcwc~"
3489  "kq]yeyeyeydq]q]q]q^qiqdqjqeqiqeqiqeqiqeqiqeqiqd{hqlpmqdqjqdqjqdqjqdqjqcqmqbqjqcqmq9pkqkpgpepgpmumpgp"
3490  "mrjpgpepfq]pmq:{epmpLzg|evbveqipdqipbqmqaqmpbq [qHqK{cpmq^plqmqkqktRqZqFqOtKq^qiqaq^rZqdy^qdqiqaqaq"
3491  "iq]q:uc{cudq_qlqlqmqjxdqiqfq\\qgqgq]q^qgqfqiqeq]q]qmrbq]qlqlqgqlqnqfqfqgq^qfqgqkr]qaq`qiqcqnqaqnqkqnq"
3492  "hrnq`q_r`q\\q[q$qjqcqjqeq]qjqdydq^qjqcqjqdq]q]s_q]qkqkqiqjqeqiqdqjqeqjqcqZsbq]qjqcqmqaqnqmqnqfs`qmq`r"
3493  "^r`qZr9pkqkphqkrcqjqeqkqcqiqet_qjqcqnq`rnqbqjqeqlqlqgqmqmqdqlqcqmqmqdqiqfqiqaqaqiqdqjqbr`q]qhqgrmqmr"
3494  "fqhqeweqfqgrYqYrdpnqnpdrirdpnqnpNq_qmp_q]qmqcyPrmqMqmpkpmqkvaplpVqRqmpkpmq=q&qjq`pmp(v_plp\\pkpmpdphq"
3495  "epkpmpjq]xdxdxdxdxdxdwdq\\q]q]q]q]q]q]q]q]qgqgqlqnqfqfqhqfqhqfqhqfqhqfqcteqnqiqgqiqeqiqeqiqeqiqbq`vbq"
3496  "jqeqjqdqjqdqjqdqjqdqjqdqjqdqjxkq]yeyeyeydq]q]q]q^qiqdqjqeqiqeqiqeqiqeqiqeqiqQqmplqdqjqdqjqdqjqdqjqcq"
3497  "mqbqjqcqmq9qlqlqgqgqgqnqmqnqgqnqjqgqgqfq]qnq:{eqnpLzg|dt`tdqipcpipbpkp`sbq Zq plq`pmq_pkqmqkqjrQqZq"
3498  "Fq'q]rkraq_rYqdy^qdqiqbq`qiq^q6uf{fuaq_qlyjzeqiqeq]qhqfq]q]qhqfqiqeq]q]qlrcq]qlqlqgqkseqhqfq]qhqfqjq"
3499  "]qaq`qiqcqnq`skshrmraq_q_q[q\\q$qjqcqjqeq]qjqdq\\q^qjqcqjqdq]q]qnq`q]qkqkqiqjqeqiqdqjqeqjqcqXqbq]qjqcq"
3500  "mqaqnqmqnqgqmq`s_q\\q`qZq7pmpnqmpgqkrcqjqeqkpbqiqeq\\qjqcs_qlqcqjqeqlqlqgqmqmqdqlqcqmqmqdqiqfqiqaq`qkq"
3501  "drjrdr_q]riqfrnqnreqhqducqhqerZqZrdwdrkrdwOq_qmp_q^w`q`q[sKplslpTplpWqQpmpkqnp<q&qjq`pmp aplp\\pkplpe"
3502  "phqepkplpjq^zfzfzfzfzfzfxcq]q]q]q]q]q]q]q]q]qhqfqkseqhqfqhqfqhqfqhqfqhqcrnreriqfqiqeqiqeqiqeqiqbq`q]"
3503  "qjqeqjqdqjqdqjqdqjqdqjqdqjqdqjqdq]q]q]q]q\\q]q]q]q^qiqdqjqeqiqeqiqeqiqeqiqeqiqQqnpkqdqjqdqjqdqjqdqjqb"
3504  "saqjqbs7qmqmqeqiqeqiqeqiqeqiqeq]qnp7q]rJrnpnresnpnsct_rcqipcqkqcqkqasaq [rkp&plpcplpnr`qkqmqkrltRqZ"
3505  "qFq'q\\qkq`q`r_pjr^qcpjrcqkrbq`rkrdpkr3sSsLrlrnrhqhqeqjreripeqjsfq]q]riqfqiqeq]q]qkrdq]qgqgqkserjrfq]"
3506  "rjrfqjrfpiraq_qkqbt`skshqkqaq`q^q[q\\q$qkrcrlrdqkpcrlrcqipdq^rlrcqjqdq]q]qmqaq]qkqkqiqjqdqkqcrlrerlrc"
3507  "q^pjqbq]rlrbs_rkrfqmq`s`r\\q`qZq6qlrfrmscrlrepkqbrkqdqkpaqjqcs`rlqcrlrernsnrgrnqnrdqlqcrnqnrdrkqdqkra"
3508  "q`qkqdqhqer^q\\rkqdwdqhqbqarjrdpYqYpbubpipbuNq_rnpmpbq^qnqnq`q`qZqIpgpRplp7pgp;q&rlr`pmp bplp[pkufpiq"
3509  "dpkukrlpcqhqfqhqfqhqfqhqfqhqfqhqfqjqcripeq]q]q]q]q]q]q]q]qjsfqkserjrfrjrfrjrfrjrfrjrdrlrfrjreqkqcqkq"
3510  "cqkqcqkqaq`q]qnplqeqkrdqkrdqkrdqkrdqkrdqkrdqksjpjqkpbqipdqipdqipdqipdq]q]q]q]qkqcqjqdqkqcqkqcqkqcqkq"
3511  "cqkq^qbqkqcrlrdrlrdrlrdrlrbsarlrbs6qkqcqkqcqkqcqkqcqkqdq\\r7q\\qFp\\p]r^rcqipcvbqkqas`r \\vOqIqlpcw_pip"
3512  "mpivnrRpZpEqbqIq^q[ubwdxdw]qcwbwaq_wcvbq]qRpSp[q^q^qhqexcxeyexdq\\xeqiqeq]q]qjrexdqgqgqjrdxeq\\xeqiqfx"
3513  "`q_war_ririqiqbqazfq[q\\q$xcwcvbwcxdq]wcqjqdq]q]qlqbq]qkqkqiqjqdwcwcwcq^wbu`wbs_rkrgqkq`q`w`q`qZq$yew"
3514  "dqmq`wdvaqjqbr`qkqcyeyewcqlsdwcxdw`sauczexdq^umteucqhqbq`xLqJsKsMq^vdxdpgpaq`qYqIqkq bqkq?{+yapmp Jp"
3515  "fpfpipcpfpiucqhqfqhqfqhqfqhqfqhqfqhqfqjxixexdxdxdxdq]q]q]q]yeqjrdxdxdxdxdxdrjrgpnwdwcwcwcwaq`q]qnuex"
3516  "dxdxdxdxdxdvnwjvbxdxdxdxdq]q]q]q]wcqjqdwcwcwcwcw^qbwbwcwcwcwaq`w`q4uauauauaucq\\r7p[qFp\\p\\p\\pbqipasap"
3517  "ip`q^y ctNqIqmqbu_phsgslrSq\\qEqbqIq^qZsawdxcu\\qbt^taq]uataq]q q]qgpiqfqfw`udwcxdqZudqiqeq]q]qirfxdq"
3518  "gqgqjrbtcqZtcqirfv_q]s_r_rirjrircqazfq[q\\q#tnqcqns`s`snqaucq\\snqcqjqdq]q]qkqcq]qkqkqiqjqbsaqnsasnqcq"
3519  "]t_t_snqaq^rkrhrkraq`w`q`qZq#smrevbs^t`s`qjqbq`qiqdqnrmqdrmrcubqkrcubqntat^r`sc|fxdq^umtcqaqhqbq^tJq"
3520  "IqIqLq]tcxLq`qYqHu `u>{+qnrmqapmp Kpepgpiuhpephscqfqhqfqhqfqhqfqhqfqhqfqhqixgudxdxdxdxdq]q]q]q]wcqjr"
3521  "bt`t`t`t`taphpgplt`s_s_s_s_q`q]qmsctnqctnqctnqctnqctnqctnqbsktgs_uauauaucq]q]q]q[saqjqbs_s_s_s_sNpms"
3522  "_snqbsnqbsnqbsnqaq`qns_q !p Zp jp#q\\q6q7q lq [sjq Qq -q OqZq]q Cq;q HqWq $rIq`qZq _q iqbqK"
3523  "qFqIq`q hp$q]u JqYpmpLp .p jp ]p Xr`q[r !p Tp\"p\\p6q6q mq Yx Qr -r Ps\\q_s"
3524  " Ipkq:q HqWq $qHq`qZq _q iqbqKqFqIq`q hp$q]t IqYpmpLq /q kq Fq_q[q #s Tp\"q"
3525  "^q6p 1p Vu Rs YsJsMy &v<s HqWq &sHtcq]t _q iqbqKqFqIq`q hp$q 2q2q /q kq Hs_"
3526  "q]s \"q (r Xy %t;r GqWq &rFscq]s ^q iqbqKqFqIq`q ,q4r 0r lr G"
3527  "r^q *q "
3528  " kr i";
3529 
3530  // Define a 47x53 font (extra-large size).
3531  static const char *const data_font47x53 =
3532  " "
3533  " 9])]2_2]T\\8^U^3] E])]"
3534  "2`4^U^>])]2_4^U^ 6^T\\5])]1_2]T\\8^U^ K])]2`4^V^3] "
3535  " "
3536  " U]*\\2a4`V\\8^U^5a F]*\\1\\X\\4^U^=]*\\"
3537  "2a5^U^ 7aV\\4]*\\1a4`V\\8^U^ J]*\\1\\X\\4^V^3\\ "
3538  " "
3539  " S],\\1\\W\\5g8^U^6c F],\\1\\V\\5^U^<],\\2]W]6^U^"
3540  " 8h3],\\0\\W\\5g8^U^ I],\\1\\V\\5^V^4\\ ;] "
3541  " "
3542  " :\\-]2\\U\\6\\V`7^U^7]U] F\\-]2\\T\\6^U^;\\-]3]U]7^U^ 8\\"
3543  "Va1\\-]1\\U\\6\\V`7^U^ H\\-]2\\T\\6^V^5] =a J] "
3544  " "
3545  " N\\/]2\\S\\7\\T]6^U^7\\S\\ E\\/]2\\R\\7^U^:\\/]3]S]8^U^"
3546  " 8\\T^/\\/]1\\S\\7\\T]6^U^ G\\/]2\\R\\7^V^6] =c L^ "
3547  " *^ U` "
3548  " O^ )\\S\\ !^$^3\\ E]"
3549  "U\\ K^$^4^ G^$^4] J^$^3\\ #^$^3\\ 4^ B[ "
3550  " &^ Xe "
3551  " S^ (\\S\\ )Z Q^&^3^2]S\\ A\\S\\ K^&^3^ F^&^4_ >]S"
3552  "\\9^&^3^2]S\\ W^&^3^ 6^ Q] M[ ?` ![1^H]?` =]4](\\ %` >b4c Bb "
3553  "?`2a .a Ib Pb Aa <a @b Fb =b F^ :] '] Da A].].].].] <_:]._ "
3554  " Xh ?c W^ @` La Pa Sa Va5^U^ @` \"f4_ >`0`*^ $^.` <^F]F^F]G`G] "
3555  " F\\S\\ ;b %a2a2a2a2a <bR\\ D`4^(^3`4`U\\8^V^6\\S\\ J^(^3`4^U^@^(^3_4^U^/^/`U\\8^(^3`"
3556  "4`U\\8^V^ K^(^3`4^V^1^9]+^V^ ?` O\\ D\\6]M] We D]1]T] 9[3bJ\\@e<])]2])\\ "
3557  " T]0d3_7h9i/_;k5f?n:f7e 3g :_8i3h@h9n?l5iB]H]C].].]J^B].`I`H_J]<g?g1g?g4hAuB]H]G]C]F]K"
3558  "_K]S^J^F^G^CrBb7]*b'_ D] :] '] Fc A].].].].] >a:].a !^T_ Bg ` Dd2_8n?"
3559  "m7g3]:rD]P]P]@g <] 8] 8] B] 3e J^K^ If7^U^+b@d Fb@f5a Ad4e-] :f Ra0d AaF\\HaF\\HeJ\\?]._0_"
3560  "0_0_0_2\\U\\0tHh@n?n?n?n?].].].]-h:_J]<g8g8g8g8g BhV]G]H]C]H]C]H]C]H]G^G^B]*d5](]2\\X\\4aW]8^V"
3561  "^6\\S\\ I](]3]X]5^U^?](]3\\W\\5^U^.^R[9aW]7](]2\\X\\4aW]8^V^ J](]2\\X\\4^V^1]8]+^V^ ?a>w "
3562  "P[ 9[/a:aQa7[ Wl \"h E]1]T]+\\R\\;[4dL]Ag=])]2])\\ U^1f8c8k;j1`;k7h?n;h9g 5i*b:_"
3563  "8k6kBl=n?l7mD]H]C].].]L_A].`I`H`K]>kAj6kAj9kBuB]H]F]E]E^L_L^R^L^D^I^BrBb7^+b(a D] ;] '] Gd"
3564  " A].].].].] ;] (b:].b #^Q] Dj !a Ff3_8n?m8i4]:rD]P]P]Bk ?_ 9] 9_ C]&[0f "
3565  "I]K]=]0g7^U^-fC\\S] IfBf6c B[S]5[S].] <i R\\W\\1]T] B\\W\\G]H\\W\\G]H[S]K]?]._0_0_0_0_2c1uIkBn"
3566  "?n?n?n?].].].]-l>`K]>k<k<k<k<k EoF]H]C]H]C]H]C]H]F^I^A],h6]*]2\\V\\6]Wa7^V^6\\S\\ H]*]2\\V]6^U"
3567  "^>]*]3]W]6^U^._V_;]Wa5]*]2\\V\\6]Wa7^V^ I]*]2\\V\\5^V^2]7]+^V^ @]W\\=v P[ 9\\1c<cSd:] "
3568  "\"o #_S^ F]1]T],]S];[5^V^N]A_T]=]*]0]*\\ U]1^T^;e8`S_<^R_2`;k8^R]?n<_T_;^S^ 6^S_."
3569  "i>_8m:`R`Cn?n?l9`QaE]H]C].].]M_@].aKaH`K]?`S`Bk8`S`Bk;_R_BuB]H]F]E]D]MaM]P]L]B^K^ArB]1]&])"
3570  "c D] <] '] G] :].].].].] ;] (^6]*^ #]P^ E^P\\ V^ H^T^4_8n?m:`S`6]:rD]P]P"
3571  "]C`S` Aa :] :a D]&[1^S\\ I^M^=]0^R[7^U^/^R^EZO\\ L^R^ N]U] :],\\0] <j M\\2]R] >\\H]B\\H]=\\M]>"
3572  "]._0_0_0_0_0_/uK`R`Cn?n?n?n?].].].]-n@`K]?`S`>`S`>`S`>`S`>`S` H`ScE]H]C]H]C]H]C]H]E^K^@],^"
3573  "T^5],]1\\V\\6\\U`7^V^6]U\\ F],]2\\T\\6^U^=],]2\\U\\6^U^-e9\\U`4],]1\\V\\6\\U`7^V^ H],]1\\V\\5^V^3]6]+^"
3574  "V^ B`1`1`1`1`6]W]>u P[ 9]2e>eUf;^ %q $^O\\ F]1]T],]S];[5]T]N\\@]P[=]*]0]2ZR\\RZ $"
3575  "]2]P]<_W]8]N]<ZL^4a;]+]MZ/]<^P^=^Q^ 7\\O]1nAa9]N_<_M]C]NaA].]+_L^E]H]C].].]N_?].aKaHaL]@"
3576  "^M^C]P_:^M^C]P_=^M\\6]6]H]F^G^D]MaM]P^N^B^K^-^B]1]&]*e D] =] '] H] 9].].].].] ;] )"
3577  "^5])^ %^O]8^3]LZ U] I^R^6a9_0]+^M^7]:]H]D]P]P]D^M^ Cc ;] ;c E]&[2^PZ H]M]<]1^-^U"
3578  "^1]L];[ N]L] Q]S] :\\,\\1] <dU\\ M\\2\\P\\ >\\H\\A\\H\\<\\M\\=]/a2a2a2a2a1_/]V];_M]C].].].].].].].]"
3579  "-]ObBaL]@^M^@^M^@^M^@^M^@^M^ J^N`D]H]C]H]C]H]C]H]E^K^@]-^Q]5].]1\\T\\7\\S]6^V^5c E].]2]S\\7^U"
3580  "^<].]2\\S\\7^U^,a6\\S]2].]1\\T\\7\\S]6^V^ G].]1\\T\\6^V^4]5]+^V^ De6e6e6e6e9\\U\\>u P[ :_3f@gVf<"
3581  "_ &r $]M[ F]1]T],\\R]>d<^T^P]A^OZ=]+].]4]T\\T] &^3^P^=[S]8[K].]4\\X];],]!]<]N]>^O^ "
3582  " 8ZM^3`P`Ba9]M^=^J\\C]K_B].],^H\\E]H]C].].]O_>].aKaHaL]A^K^D]N^<^K^D]N^>]JZ6]6]H]E]G]C]MaM]"
3583  "O^P^@^M^-^A]1]&]+_W_ D] >] '] H] 9] B].] ;] )]4](] %]N]:c6] G] J^P^7a8"
3584  "_1],^K^;c=]H]D]P]P]E^K^ Ee <] <e F]&[2] =^O^<]1] 0\\H\\<\\ P\\H\\ R\\Q\\+]3\\,\\2] <eU\\ M\\3]P\\ >"
3585  "\\I]A\\I]<\\N]=]/a2a2a2a2a2a1]U]<^J\\C].].].].].].].]-]K_CaL]A^K^B^K^B^K^B^K^B^K^ K]K^D]H]C]H]"
3586  "C]H]C]H]D^M^?]-]P]4]0]1\\R\\ Ha C]0]2]R] E]0]2\\Q\\ 9c 9]0]1\\R\\ !]0]1\\R\\ ?]4] Di:i:i:i:i"
3587  ";\\6]G] P\\ :`5g@gWh>a (_ J]KZ F]1]T],\\R\\?h>]R]P\\@]1]+].]3^V\\V^.] T]2]N]5]8ZJ]-]"
3588  "6]X];]-]!^=]L]?]M] *]5_J_Ec:]L^>]H[C]I^C].],]F[E]H]C].].]P_=].]X]M]X]HbM]A]I]D]M]<]I]D]"
3589  "M]?]%]6]H]E]G]C^NaN^N]Q^>^O^-^@]0]'],_U_ &] '] H] 9] B].] ;] )]4](] %]N]:d7] "
3590  " F] K]N]8c8^1],]I]>i@]H]D]P]P]E]I] Fg =] =g G]&[2] <]O];]1] 1\\F\\=\\ Q\\F\\ S\\Q\\+]3\\."
3591  "] IeU\\ M\\3\\N\\ ?\\I\\@\\I\\=]M\\<]0c4c4c4c4c3a1]U]<]H[C].].].].].].].]-]J_DbM]A]I]B]I]B]I]B]I]"
3592  "B]I] L]J_E]H]C]H]C]H]C]H]C^O^>].]N] .] '`X_ I] FbWa=bWa=bWa=bWa=bWa<"
3593  "\\6^I^ ?Z2[ :a5gAiXh?c *^ H] 7]1]T]-]S]Aj>]R]Q]@]1],],\\1^X\\X^,] T]3]L]6]'].]7]W]"
3594  ";]-]!]<]L]?]M^ +]6^F^F]W]:]K]?]FZC]H^D].]-]DZE]H]C].].]Q_<].]X]M]X]H]X]M]B]G]E]M^>]G]E]"
3595  "M^@]%]6]H]E^I^B]O^X]O]M^R^=]O^-^@]0]']-_S_ '] '] H] 9] B].] ;] )]4](] %]N]:e8"
3596  "_ H] L]M]8]W]7^2]-]G]AmB]H]D]P]P]F]G] Hi >] >i J[3] ;^Q^;]1] 2\\RbT\\Ge R\\VdR\\ T\\"
3597  "Q\\+]4\\2a IfU\\ M\\3\\N\\ ?\\J\\?\\J\\AaM\\ G]W]4]W]4]W]4]W]4]W]4c3^U]=]FZC].].].].].].].]-]H]D]X]"
3598  "M]B]G]D]G]D]G]D]G]D]G]A[H[B]J`E]H]C]H]C]H]C]H]B]O^>g8]N] 1]T_ 3[ 9] "
3599  "G_O^?_O^?_O^?_O^?_O^=\\5]I^ @\\3[ ;c6gAy?d7`8]L]7^7]L]>^ H] 6]1]T]-]S]B_W[U]>]R]R]?]1"
3600  "],],]0d*] T]3]L]6]'].]7\\V];].] ]<]L]@]K] 7Z PZ X]7^D^G]W]:]K]?]/]G]D].]-]/]H]C].].]R_;]"
3601  ".]X^O^X]H]X^N]B]G]E]L]>]G]E]L]@]%]6]H]D]I]A]O]W]O]L^T^<^Q^-^?]0]'].^O^ Sb7]U`2b4`U]8a8])`"
3602  "7]T_ M].]%_O_@_2`0`3`/_3c9] )]4](] N_6]N]3^7a/c0_ <^ D[U^ Ga N]L]9]W]6^3]-]G]B`W"
3603  "]W`C]H]D]P]P]F]G] I_X]X_ ?] ?_X]X_ Nb7]2ZFZ=]Q]:]0] 3[SfU[Ig R[UfS[ T\\Q\\+]5]2a IfU\\ M"
3604  "\\3\\N\\ ?\\K]?\\K]AaN] G]W]4]W]4]W]4]W]4]W]4]W]3]T]=]/].].].].].].].]-]G]E]X^N]B]G]D]G]D]G]D]G"
3605  "]D]G]B]J]C]KbF]H]C]H]C]H]C]H]B^Q^=j;]P_9b3b3b3b3b3b3bN`Bb3a2a2a2a V_2_2`1`1`1`1` ;aU] "
3606  " :]U` S^T]U^A^L^A^L^A^L^A^L^?]5]I] @^5\\ <e7gAy@f;e:]L]8`8^N^?^ G] 6]1]T]-\\R\\A]U["
3607  "RZ>]R]R\\>]1],],].`(] U^3]L]6]'].]8]V];].]!^<]L]@]K] :] P]#^8^A]I^W^;]K]@].]G^E].].].]H]"
3608  "C].].]S_:].]W]O]W]H]W]N]C]E]F]L]?]E]F]L]@]%]6]H]D]J^A]O]W]O]L^U^:^S^-^>]0^(]/^M^ Wh:]Wd6f"
3609  "8dW]:e>h2dW]?]Vd<].].]O_>].]WdScK]Vd8f;]Wd7dW]?]Wa6h>h6]L]B]I]A]P`P]K^L^B^K^@l4]4](] PdU"
3610  "]A]N]2^8e5g;]Vd?^J^8]6]L] E]V`>pA]S]S]:e6kDo>]L]:^W^6^4].]E]D_U]U_D]H]D]P]P]G]E] K_W]W_ @]"
3611  " @_W]W_ Qf9]3\\H\\>^S^:]0_ 6[ThT[K]Q\\ S[T\\R]S[ U]S]+]6],] ?]L]@fU\\ M\\3\\N\\ ?\\K\\>\\K\\;]O\\ G"
3612  "^W^6^W^6^W^6^W^6^W^5]W]4^T]>].].].].].].].].]-]G^F]W]N]C]E]F]E]F]E]F]E]F]E]D_L_E]K]W]F]H]C"
3613  "]H]C]H]C]H]A^S^<k<]Ra<h9h9h9h9h9h9hTeFf7e6e6e6e;].].].]\"^;]Vd8f7f7f7f7f/^6eX]@]L]?]L]?]L]?"
3614  "]L]B^K^?]Wd>^K^ O]S]S]B]I]B]I]B]I]B]I]@]5^K^ @]4[ ;f8gAyAg<h<]L]8`7]N]>] F] 6]1]T]"
3615  "-\\R\\B]T[6]R]S]>^2]-]*\\.`(] U]2]L]6]'].]9]U];].]!];]L]@]K] =` P`'^7]?\\I]U];]K]@].]F]E].]"
3616  ".].]H]C].].]T_9].]W]O]W]H]W^O]C]E]F]L]?]E]F]L]@]%]6]H]C]K]@^P]W]P^K^V^9]S]-^=]/](]0^K^ Xi"
3617  ";]Xf9h9fX]<h?h3fX]?]Xg=].].]P_=].]XfVfL]Xg:h<]Xf9fX]?]Xb7i>h6]L]A]K]@^Q`Q^J^N^@]K]?l4]4](]"
3618  " QfW^A]O^1]6f9h;]Xg@_K]7]6]L]=]G]C^Wc@pA]S]S]<h9mDo>]L]:]U]5^5].]E]E^S]S^E]H]D]P]P]G]E]@"
3619  "Z+]V]V^-Z4]5ZKZ:]V]V^ Sh9]4^J^>]S]9]._ 8[U_Q[T[L]P\\ S[T\\Q]T[ T]U]*]7]*] @]L]@fU\\ M\\3\\N"
3620  "\\ ?\\L]>\\L]:]Q]:]1]U]6]U]6]U]6]U]6]U]6^W^5]S]>].].].].].].].].]-]F]F]W^O]C]E]F]E]F]E]F]E]F]"
3621  "E]C_N_D]L^W]F]H]C]H]C]H]C]H]@]S];]P_=]S^8i:i:i:i:i:i:iVgIh9h9h9h9h<].].].]'d<]Xg:h9h9h9h9h"
3622  "0^8k?]L]?]L]?]L]?]L]A]K]>]Xf>]K] O]R]R]D]G]D]VZOZV]D]KZV]D]G]A]4]K] @]3[ <g7fAyBi>j=]L]8"
3623  "`7]N]?] F^ 6]1]T]5uI]T[6]R]S\\<^3]-]*]1d*] U]3]J]7]'].]9\\T];].\\Ua-^;]L]@]K^?].] Uc "
3624  "Pc+_8]>]J]U];]K]@].]F]E].].].]H]C].].]U_8].]W^Q^W]H]V]O]C]E]F]L]?]E]F]L]@^&]6]H]C]K]?]Q^V]"
3625  "Q]I^X^8^U^.^<]/](]1^I^ ]R_<aT_;_R\\:^Tb=_S^@h4_Ub?bT^=].].]Q_<].aT_X]T^LbT^;_T_=aT_;^Tb?aT"
3626  "Z8_R]>h6]L]A]K]?]Q`Q]H^P^?]K]?l4]4](] R^U^W]@]O]0^7g;_S];bT^@`L]8_7]L]>]E]E^W]V]@pA]S]S]"
3627  "=_T_<oDo?]K^;]U]5_6].\\D]E]R]R]E]H]D]P]P]G]E]A\\+[U]U\\,\\6]6\\L\\;[U]U\\ S_W[V\\9]3^V`V^=^U^9]/a"
3628  " :[T]G[M\\O\\1ZQZ M[S\\P\\S[ Ud)]8](\\ @]L]@fU\\ M\\3\\N\\9ZQZ0\\L\\=\\L\\8\\Q\\9]1]U]6]U]6]U]6]U]6]U]6"
3629  "]U]5]S]>].].].].].].].].]-]F]F]V]O]C]E]F]E]F]E]F]E]F]E]B_P_C]L]V^G]H]C]H]C]H]C]H]@^U^;]N^>"
3630  "]T]6]R_;]R_;]R_;]R_;]R_;]R_;]R_X_T^K_R\\:_S^;_S^;_S^;_S^=].].].]*h=bT^;_T_;_T_;_T_;_T_;_T_1"
3631  "^9_T`>]L]?]L]?]L]?]L]A]K]>aT_?]K] P]Q]R]E]F]E]V\\Q\\W]E]K\\W]E]F]A]4^L] A^@ZN\\ =i8e@yCk?^R^"
3632  "=]L]9b8]O^?] Im B]1]T]5uI]T[6]S^T]<^3]-]*]3^X\\X^,] V^3]J]7](^/]9]T];e7]We/]9]N]?]K"
3633  "^?].] Wd Nd._8]O`U\\T\\K]S]<]L^A]-]F^F].]/]-]H]C].].]V_7].]V]Q]V]H]V^P]D]C]G]L]@]C]G]L]?^']6"
3634  "]H]C^M^?]Q]U]Q]Ic6^W^._<]/^)]2^G^ !ZM^=`Q^=^NZ;^Q`>^P^=].^Q`?`Q^>].].]R_;].`R^X\\R^M`Q^=^P^"
3635  ">`Q^=^Q`?`1]MZ;].]L]A^M^?]Q`Q]G^R^>^M^1^4]4](] D]P^A]R^X]@]P^/]9^Vb=^NZ;`Q^AaN^8_7]L]>]E]"
3636  "F^V]U]>]P]>]S]S]>^P^>`T`7]6]J]<]S]5^6]/]C]G]Q]Q]F]H]D]P]P]H]C]C^&]TZ,^7]7^N^6]TZ H]/^U[TZ9"
3637  "]2n;]U]8]0d <[U]F[M\\P]2[R[ M[S\\P\\S[ Tb(]9]'\\ @]L]@fU\\ M\\3]P]9[R[1\\M\\<\\M\\7\\R\\8]2]S]8]S]8]"
3638  "S]8]S]8]S]7]U]6]R]?]-].].].].].].].]-]F]F]V^P]D]C]H]C]H]C]H]C]H]C]B_R_C]L]T]G]H]C]H]C]H]C]"
3639  "H]?^W^:]M]>]U^6ZM^<ZM^<ZM^<ZM^<ZM^<ZM^<ZMbP]M^NZ;^P^=^P^=^P^=^P^>].].].]+i=`Q^=^P^=^P^=^P^"
3640  "=^P^=^P^2^:^P^>]L]?]L]?]L]?]L]A^M^>`Q^@^M^ P]Q]Q]F]E]F]W^S^W]F]L^W]F]E]B]3]M^ B^B^O[ =k8"
3641  "d?xClA^P^>]L]9]X]8^P]>\\ Hl A] 9uI]T[5]T]T]:^ =]*]5^V\\V^.] V]2]J]7](]/^:]S];h:]Xg0]"
3642  "9^P^?]K^?].]!e Je2_7\\PdW\\S\\L]S]<]M^@]-]E]F].]/]-]H]C].].]X_5].]V]Q]V]H]U^Q]D]C]G]L]@]C]G]M"
3643  "^?`)]6]H]B]M]>]Q]U]Q]Hb5c-^;].])] B]=_O]=].]O_>]N^>].]O_?_O]>].].]S_:]._P`P]M_O]=]N]>_O]"
3644  "=]O_?_1]-].]L]@]M]>]RbR]G^R^=]M]1^3]4](] FaSaD^Qa?]R_.]9]R`>]._O]>^N]8`7]L]>]E]G^U]U^?]P]"
3645  ">]S]S]>]N]>^P^7]6]J]<]S]4^7]/]C]G]Q]Q]F]H]D]P]P]H]C]D_&]&_8]8_N_7] B]/]T[3]1l:^W^8]1]W` >\\"
3646  "U\\E\\N\\P]3\\S\\ N\\S\\P\\S\\ S_']:]&\\ @]L]@fU\\ M\\2\\P\\8\\S\\2\\N]<\\N]7\\S]8]2]S]8]S]8]S]8]S]8]S]8]S]"
3647  "7]R]?]-].].].].].].].]-]E]G]U^Q]D]C]H]C]H]C]H]C]H]C]A_T_B]M]S]G]H]C]H]C]H]C]H]>c9]M^?]U]']"
3648  ".].].].].].`O^N].]N^>]N^>]N^>]N^?].].].],_R^>_O]=]N]=]N]=]N]=]N]=]N]2^:]O_?]L]?]L]?]L]?]L]"
3649  "@]M]=_O]?]M] O\\P]Q]F\\D]F\\U^U^V]F\\L^V]F\\D]B]3]M] RuJ`O[ >m9c>wCmA]N]>]L]9]X]7]P]?] "
3650  "Im A] 2\\R\\A]T[5^V^T\\:` ?](\\6]T\\T]/] V]2]J]7])^1_9]S];i;bS^2^8^S_>]K^?].]$e@u@e6_7]QfX\\S\\"
3651  "M^S^=]N^?]-]E]F].]/]-]H]C].].c4].]U]S]U]H]T]Q]D]C]G]M^@]C]G]M]=c-]6]H]B]M]>^R]U]R^G`4c.^:]"
3652  ".])] B]=^M]?^/]M^?]L]>]/]M^?^N^?].].]T_9].^O_O^N^N^?]M^?^M]?]M^?^0]-].]L]@]M]>^S]X]S^F^T"
3653  "^<^O^2_3]4](] GcUcE]Pa?]Vb-]:]O_?].^N^>]O^8a8]L]?]C]H]T]T]?]P]>]S]S]?]L]@^N^8]6]J]=^S^4^8"
3654  "]/]C]H^Q]Q^G]H]D]P]P]H]C]E_%]%_9]9_L_8] B]0^T[3]0_T_>cWc=]1]U_ ?[U\\C[N]R^4]T] N[R\\Q]R[ 'u"
3655  "G]&] @]L]?eU\\ M\\2]R]8]T]3\\N\\;\\N\\7]S\\7]3^S^:^S^:^S^:^S^:^S^9]S]8^R]?]-].].].].].].].]-]E]G"
3656  "]T]Q]D]C]H]C]H]C]H]C]H]C]@_V_A]N]R]G]H]C]H]C]H]C]H]>c9]L]?]U]'].].].].].]._M]O^/]L]?]L]?]L"
3657  "]?]L]?].].].]-^O]>^N^?]M^?]M^?]M^?]M^?]M^ I]O`?]L]?]L]?]L]?]L]@^O^=^M]@^O^ P]P]P\\G]C\\G]T^"
3658  "W^T\\G]M^T\\G]C\\B]3^O^ RuJ[X]P[ >o=\\XaX]BwDoC]L\\>]L]:^X^8]P]?] E] 5] 3]S]A^U[4dT];b @"
3659  "](]6ZR\\RZ.] V]2]J]7]*^7d8]R];]R_<aQ^3]5f<^M_?].]'e=u=e:_6\\Q^S`S]N]Q]=l>]-]E]Fm>k=]-rC].]"
3660  ".b3].]U]S]U]H]T^R]D]C]G]M]?]C]G]N^<f1]6]H]B^O^=]S^U^S]F_2a.^9].])] A]>^M]?].]M^?]L]>]/]M"
3661  "^?^M]?].].]U_8].^N^N]N^M]?]L]?^M]?]M^?^0]-].]L]@^O^=]S]X]S]D^V^:]O]2_2]4](] H\\U^W]U\\E]Pa?"
3662  "]Vb-];]M^?].^M]>^P]7a8]L]?]C]H]T]T]?]P]>]S]S]?]L]@]L]8]6p=]Q]3^9]/]C]H]P]P]G]H]C]Q]Q]G]ViV"
3663  "]F_$]$_:]:_J_9] B]0]S[3]0]P]>o=]2]S_ @[U\\C[M]T_5^U^;u O[R\\R]Q[ 'uH]/ZQ] ?]L]?eU\\ M\\1]T]7^"
3664  "U^4\\O]O]I\\O]T`MZQ]S]O]E]3]Q]:]Q]:]Q]:]Q]:]Q]:^S^9]QmO]-m>m>m>m>].].].]1hL]G]T^R]D]C]H]C]H]"
3665  "C]H]C]H]C]?_X_@]O]Q]G]H]C]H]C]H]C]H]=a8]L]?]U]&].].].].].].^M]O].]L]?]L]?]L]?]L]?].].].].^"
3666  "M]?^M]?]L]?]L]?]L]?]L]?]L] I]Pa?]L]?]L]?]L]?]L]?]O]<^M]?]O] O]P]P\\G]C\\G]ScS\\G]N^S\\G]P]P\\B"
3667  "]2]O] QuF]Q[ >oAqDuDqD]L]?]L]:^X^8^R^?\\ D] 5] 3]S]@`X[3bS\\R^G]W^N] P](].\\&] W]1]J"
3668  "]7]*^7c8]Q];ZM^=`O^4]4d:]M_?].])d:u:d=_5\\R]O^R\\N]Q]=j<]-]E]Fm>k=]-rC].].a2].]U^U^U]H]S]R]D"
3669  "]C]G]N^?]C]G]P_:g3]6]H]A]O]<]S]S]S]E^1_.^8]-]*] A]>^M]?]/^M^?]K]?]0^M^?]L]?].].]V_7].]M]"
3670  "M]N]L]@^L]?^M]@^M^?]/]-].]L]?]O]<]S]X]S]C^X^9]O]2^1]4](]0_IZ O[R\\X]S\\G^O_>]Vd9_U];]L]?].]L"
3671  "]=]P]8]X^9]L]?]C]I^T]S]@]P]>]S]S]?]L]@]L^9]6p=]Q]3^9]/]C]H]P]P]G]H]C]Q]Q]G]ViV]G_#]#_;];_H"
3672  "_:] B]0]S[3]0\\N\\>o=]2]Q^ A[U\\C[LcX\\6]T]9u O[RfP[ 'uIf7e >]L]>dU\\<] :f5d4]T]:fT\\O^NfT\\UdOeR"
3673  "\\O^F^3]Q]:]Q]:]Q]:]Q]:]Q]:]Q]:^QmO]-m>m>m>m>].].].]1hL]G]S]R]D]C]H]C]H]C]H]C]H]C]>d?]P^Q]G"
3674  "]H]C]H]C]H]C]H]<_7]L]?]U^'].].].].].].^L]P].]K]@]K]@]K]@]K]@].].].].]L]?]L]@^L]@^L]@^L]@^L"
3675  "]@^L] I]Q]X^@]L]?]L]?]L]?]L]?]O]<^M]?]O] O\\WmX]H\\WmX]H\\QaR]H\\N^R]H\\O]P]C]2]O] QuF]R\\ ?qC"
3676  "sDtDrE]L]?]L]:]V]7]R]>x '] 5] 3\\R\\?e3^R\\SbJ^V^O] P](].\\&] W]1]J]7]+^6e:]Q]-^>_M]5^6"
3677  "h<^O` Qe8u8e@^5]R\\M]R\\O^Q^>m?]-]E]Fm>k=]KdFrC].].b3].]T]U]T]H]S^S]D]C]G]P_>]C]Gk6f5]6]H]A"
3678  "^Q^<]S]S]S]F_1_/_8]-]*] A]>]K]A].]K]@]J]?]0]K]?]L]?].].]W_6].]M]M]N]L]@]J]@]K]A]K]?]/^.]"
3679  ".]L]?]O]<]T^W]T]C^X^9^Q^3^1]3]']3dN\\ P\\R`Q[G]N_>]Q`;bW];\\K^?]/]L]=]Q^8]W]9]L]?]C]I]S]S]@]P"
3680  "]>]S]S]@]J]B^L^9]6p>^Q^4^9]/]C]H]P]P]G]H]C]Q]Q]G]ViV]H_\"]\"_<]<_F_;] B]1]R[3]1]N]8a6]2]P^ B"
3681  "[U\\C[K`V\\7]T]8u O[RdN[ 'uIf5a <]L]=cU\\<] :f3`1]T];fU\\N^NfU\\T[S]NaQ\\N^G^3^Q^<^Q^<^Q^<^Q^<^Q"
3682  "^;]Q]:]PmO]-m>m>m>m>].].].]1hL]G]S^S]D]C]H]C]H]C]H]C]H]C]=b>]P]P]G]H]C]H]C]H]C]H]<_7]L]?]U"
3683  "_(].].].].].].]K]Q].]J]A]J]A]J]A]J]@].].].].]L]?]L]@]J]A]J]A]J]A]J]A]J] K]P\\V]@]L]?]L]?]L]"
3684  "?]L]?^Q^<]K]@^Q^ O\\WmX]H\\WmX]H\\P_Q]H\\O^Q]H\\O]P]C]2^Q^ D^<]R[ >qDuEsCqD]L]?]L]:]V]7]R]>x "
3685  " '] 5] 3\\R\\=f+]TdL^T^P] P](].\\2u *]1]J]7],^-_=]P],]>_M]5]7_R^<^Qa Sd .dC^4\\R]M]R\\O]O"
3686  "]>]N_@]-]E]F].]/]KdF]H]C].].]X^4].]T]U]T]H]R]S]D]C]Gk=]C]Gj1c6]6]H]@]Q];^T]S]T^Ga1].^7]-]*"
3687  "] Lh>]K]A].]K]@]J]?]0]K]?]L]?].].]X_5].]M]M]N]L]@]J]@]K]A]K]?]._0].]L]>]Q];^U]V]U^Bb7]Q]"
3688  "3^1^3]'^6iS^ P[P^P[G]N_>]N^=dX]<]J]>^1]L]=^R]8^W]9]L]@]A]J]S]S]@]P]>]S]S]@]J]B]J]9]6]J]>]O"
3689  "]5^8]/]C]H]P]P]G]H]B]R]R]F]C]Iz<]<z=]=z<] B]1]R[7j:\\L\\7_5]2]P^ B[U\\C[ V]T]7u O[R\\U^O[ T] "
3690  " ]L];aU\\<] I]T],]O[X\\>]K]@]O[X\\I`3]O]<]O]<]O]<]O]<]O]<]O];]P]?]-].].].].].].].]-]E]G]R]"
3691  "S]D]C]H]C]H]C]H]C]H]C]<`=]Q]O]G]H]C]H]C]H]C]H];]6]L]?]T_4h9h9h9h9h9h9hK]Q].]J]A]J]A]J]A]J]"
3692  "@].].].]/]J]@]L]@]J]A]J]A]J]A]J]A]J]?tG]Q\\U]@]L]?]L]?]L]?]L]>]Q];]K]?]Q] N\\WmX]H\\WmX]H\\P_"
3693  "Q]H\\P^P]H\\O]P]C]1]Q] C]:]S[ ?sEvEqAoC]L]?]L];^V^8^T^>x '] 5] 4]S]<g-\\T^V^M]S_Q\\ O](]"
3694  ".\\2u Se =^1]J]7]-^*^?]O],^?^K]7^7]N]<^Sb Sa (aC]3\\R\\K\\R\\P^O^?]L^A]-]E]F].]/]KdF]H]C].].]W"
3695  "^5].]T^W^T]H]R^T]D]C]Gj<]C]Gj-`7]6]H]@]Q]:]U^S^U]Fb2]/^6]-^+] Nj>]K]A].]K]@p?]0]K]?]L]?]"
3696  ".].b3].]M]M]N]L]@]J]@]K]A]K]?].c4].]L]>]Q]:]U]V]U]@`6^S^4^5b2]&b<u P[O]P\\H]N^=]M]>^Ua<]J]="
3697  "c7]L]<]S^8]V^:]L]@]A]J]S]S]@]P]>]S]S]@]J]B]J]9]6]J]?^O^7^7]/]C]H]P]P]G]H]B]R]R]F]C]Iz<]<z="
3698  "]=z<] B]1]R[7j:\\L\\7_ C^P] B[U\\C[ W]T] W] O[R\\T^P[ T] ]L]7]U\\<] H]T]-\\O\\X\\>\\I\\@\\O\\X\\J`"
3699  "3^O^>^O^>^O^>^O^>^O^=]O]<^P]?]-].].].].].].].]-]E]G]R^T]D]C]H]C]H]C]H]C]H]C];^<]R]N]G]H]C]"
3700  "H]C]H]C]H];]6]L]?]S`8j;j;j;j;j;j;|Q].pApApAp@].].].]/]J]@]L]@]J]A]J]A]J]A]J]A]J]?tG]R]U]@]"
3701  "L]?]L]?]L]?]L]>^S^;]K]?^S^ N\\WmX]H\\WmX]H\\QaR]H\\Q^O]H\\O]P]C]1^S^ D]9]T\\ ?sFwDo?nC]L]?]L];"
3702  "]T]7]T]=] Hj ?] 4]S]8d/]T]T]N^R_R\\ O](] =u Se =]0]J]7].^(]?]O]+]?^K]7]7]L]<gX] Sa ("
3703  "aC]3\\R\\K\\R\\P]M]?]K]A]-]E]F].]/]D]F]H]C].].]V^6].]S]W]S]H]Q]T]D]C]Gg9]C]G]Q_,^7]6]H]@^S^:]U"
3704  "]Q]U]G^X]2]0^5],]+] Pl>]K]A].]K]@p?]0]K]?]L]?].].a2].]M]M]N]L]@]J]@]K]A]K]?]-f8].]L]>^S^"
3705  ":]U]V]U]?^4]S]4^4`0]$`<^Si O[O\\O\\H]N^=]M^@^S`<]J]=c7]L]<]S]8^U]:]L]@]O]O]J]S]S]@]P]>]S]S]@"
3706  "]J]B]J]9]6]J]?]M]7]6]/^E^H]P]P]G]H]A]S]S]E]C]Iz<]<z=]=z<] B]1]R[7j:\\L\\6] A^Q] B[U\\C[Ni:]T]"
3707  " V] O[R\\S]P[ T] ]L]6\\U\\<] Dh2]T]/]P\\W\\?]I\\A]P\\W\\K`2]M]>]M]>]M]>]M]>]M]>^O^=]O]?]-].].]"
3708  ".].].].].]-]E]G]Q]T]D]C]H]C]H]C]H]C]H]C]<`=]S]M]G]H]C]H]C]H]C]H];]6]M^?]R`;l=l=l=l=l=l=~Q]"
3709  ".pApApAp@].].].]/]J]@]L]@]J]A]J]A]J]A]J]A]J]?tG]S]T]@]L]?]L]?]L]?]L]=]S]:]K]>]S] M]P]P\\G]"
3710  "C\\G]ScS\\G]S^N\\G]P]P\\B]0]S] D]7\\T[ >sFwCn?mB]L]?]L];]T]7]T]=] Hi >] 4]S]7[Xa1]T^T^O]"
3711  "P_T] O](] =u Se =]0]J]7]/^'^A]N]+]?^K]7]8^L^<eW] Sd .dC]3\\R\\K\\R\\P]M]?]K]A]-]E]F].]/]D]F]H"
3712  "]C].].]U^7].]ScS]H]Q^U]D]C]G]/]C]G]O^,^8]6]H]?]S]9]U]Q]U]H^W^3]1^4],]+] Q`P]>]K]A].]K]@p"
3713  "?]0]K]?]L]?].].b3].]M]M]N]L]@]J]@]K]A]K]?]+e9].]L]=]S]9]V]T]V]@_4]S]5_4b2]&b<\\Nd M[O]P\\H]N"
3714  "^=]L]@]Q_<]J]?e7]L];]T]8]T]:]L]@]O]O]J]S]S]@]P]>]S]S]@]J]B]J]9]6]J]?]M]8^6].]E]G]P]Q^G]H]A"
3715  "^T]T^E]C]Iz<]<z=]=z<] B]1]R[3]1\\L\\6] A_R] B\\U\\E\\Ni:]T] V] O\\S\\R]R\\ T] ]L]6\\U\\<] Dh2]T]"
3716  "/\\O[V\\?\\H\\A\\O[V\\L`1]M]>]M]>]M]>]M]>]M]>]M]>^O]?]-].].].].].].].]-]E]G]Q^U]D]C]H]C]H]C]H]C]"
3717  "H]C]=b>]T]L]G]H]C]H]C]H]C]H];]6]M]>]Qa>`P]>`P]>`P]>`P]>`P]>`P]>`PoQ].pApApAp@].].].]/]J]@]"
3718  "L]@]J]A]J]A]J]A]J]A]J]?tG]T]S]@]L]?]L]?]L]?]L]=]S]:]K]>]S] L\\P]P\\F\\C\\F\\T^W^T\\F\\T^M\\F\\C\\B]"
3719  "0]S] E^7]U[ >sFwBl=kA]L]?]L]<^T^8^V^=] Ij >] <u=[U^1\\S]R]O]O_U\\ N](] 1] Ge =]0]J]7]"
3720  "0_&]A]N]+]?^K]8^8]J]:aU\\ Pe 4eA]3\\R\\K\\R\\Qo@]J]A].]F^F].].]E]F]H]C].].]T^8].]RaR]H]P]U]C]E"
3721  "]F].]E]F]N^,]8]6]H]?]S]9^V]Q]V^H^V^4]2_4],]+] Q]M]>]K]A].]K]@],]0]K]?]L]?].].c4].]M]M]N]"
3722  "L]@]J]@]K]A]K]?](d;].]L]=]S]9^W]T]W^@`5^U^5^/_3]'_8ZJ` K[O]P\\H]N^=]L]@]P];]J]@_0]L];]U^9^T"
3723  "^;]L]@]O]O]J]S]S]@]P]>]S]S]@]J]B]J]9]6]J]@^M^:^5].]E]F]Q]Q]F]H]@^U]U^C]E]G_\"]\"_BZT]TZB_F_;"
3724  "] B]1]R[3]1\\L\\?o I_S] A[U]F[ V]T] W] N[S\\R]R[ S] ]L]6\\U\\ ']T]/\\O\\V\\@\\H\\A\\O\\V\\M_0o@o@o"
3725  "@o@o?m>l>].].].].].].].].]-]F^G]P]U]C]E]F]E]F]E]F]E]F]E]=d?^V]L]F]H]C]H]C]H]C]H];]6]N^>]O`"
3726  "?]M]>]M]>]M]>]M]>]M]>]M]>]M]?].].].].]-].].].]/]J]@]L]@]J]A]J]A]J]A]J]A]J] K]U]R]@]L]?]L]?"
3727  "]L]?]L]=^U^:]K]>^U^ L\\P]Q]F\\D]F\\U^U^V]F\\U^M]F\\D]B\\/^U^ OuD]V[ =sFwBk;i@]L]?]L]<]R]7]V];]"
3728  " F^ Nu=[T^3]S]R]O]N_V\\ N](] 1] ].]L]6]1_%]Aq0]>]K]8]7]J]/] Md:u:d>]3\\R\\K\\S\\Po@]"
3729  "J]A].]F]E].].]E]F]H]C].].]S^9].]RaR]H]P^V]C]E]F].]E]F]M],]8]6]H]>]U^8]W^Q^W]H^U^4]2^3]+],]"
3730  " R^M]>]K]A].]K]@],]0]K]?]L]?].].]X_5].]M]M]N]L]@]J]@]K]A]K]?]$`;].]L]=^U^8]W]T]W]@b5]U]5"
3731  "^,]3]'] J\\Q_Q[G]N^=]L]A]O];]J]@].]L];]U]8]R];]L]@]O]O]J]S]S]@]P]>]S]S]@]J]B]J]9]5]L]?]K];"
3732  "^4].^G^F]Q]Q]F]H]?_W]W_B]E]F_#]#_B\\U]U\\B_H_A\\U]U[ H]1]R[3]1]N]?o H`V] @[T]G[ U]T] X] N[S\\Q"
3733  "]S[ S] ]L]6\\U\\ (]T]/]P\\U\\A]I]B]P\\U\\M^/o@o@o@o@o@o@m>].].].].].].].].]-]F]F]P^V]C]E]F]"
3734  "E]F]E]F]E]F]E]>_X_?]W^L]F]H]C]H]C]H]C]H];]6]P_=]M^@^M]?^M]?^M]?^M]?^M]?^M]?^M]?].].].].]-]"
3735  ".].].]/]J]@]L]@]J]A]J]A]J]A]J]A]J] K]U\\Q]@]L]?]L]?]L]?]L]<]U]9]K]=]U] K]Q]Q]F]E]F]W^S^W]F"
3736  "]W^L]F]E]B\\.]U] NuC\\V[ =eXZXdFgXhAi9h@]L]?]L]<]R]7]V];] E] Nu=[S]3\\R]R]O]M_X\\ M]("
3737  "] 1] ].]L]6]2_$]Aq0]>]K]8]7]J]/] Ke=u=e<]3\\R\\K\\S\\Po@]J]A].]F]E].].]E]F]H]C].].]R^:].]Ra"
3738  "R]H]O^W]C]E]F].]E]F]M^-]8]6]H]>]U]7]W]O]W]I^S^5]3^2]+],] R]L]>]K]A].]K]@],]0]K]?]L]?].]."
3739  "]W_6].]M]M]N]L]@]J]@]K]A]K]?]\"_<].]L]<]U]7]W]T]W]Ac5^W^6^+^4](] H[R\\X]S\\G]N^=]L]A]O];]J]A"
3740  "^.]L]:]W^9^R];]L]@]O]O]J]S]S]@]P]>]S]S]@]J]B]J]9]5]L]?]K];^4]-]G]D]R]R]E]H]>kA]E]E_$]$_B^V"
3741  "]V^B_J_A^V]V] I]1]R[3]0\\N\\>o G`X] ?\\U_Q[T\\ T]T] ] N\\T\\Q]T\\ S] ]L]6\\U\\ )]T].\\P\\T\\A\\I]A"
3742  "\\P\\T\\N^.o@o@o@o@o@o@m>].].].].].].].].]-]F]F]O^W]C]E]F]E]F]E]F]E]F]E]?_V_@]W]K]F]H]C]H]C]H"
3743  "]C]H];]6k<]L^A]L]?]L]?]L]?]L]?]L]?]L]?]L]?].].].].]-].].].]/]J]@]L]@]J]A]J]A]J]A]J]A]J] K]"
3744  "V\\P]@]L]?]L]?]L]?]L]<^W^9]K]=^W^ J]R]R]D]G]D]W\\Q\\W]D]W\\L]D]G]A\\.^V] NuC]W[ <cWZXdEfXh@g8"
3745  "g?]L]?]L]=^R^8^X^:] F] G\\R\\5[S]4]R]R]O]Lb M](\\ 0] ].]L]6]3_#]Aq0]>]K]9]6]J]/] H"
3746  "e@u@e H\\R]M]T]Q^J]A]J]@]/]G^E].]-]F]F]H]C].].]Q^;].]Q_Q]H]N]W]B]G]E]-]G^F]L]-]8]6]I^>^W^7]"
3747  "W]O]W]I^R^6]4^1]+],] R]M^>^M^@]/^M^?]-]0^M^?]L]?].].]V_7].]M]M]N]L]@^L]?^M^A^M^?] ]<].]L"
3748  "]<]U]7]X]R]X]B^W^5]W]6^)]4](] H\\T]W]U\\F]O_=]L]A]P^;^L^A]-]L]:]W]8]P]<]L]@]O]O]J^T]T]?]P]>"
3749  "]S]S]@^L]A^L]8]5]L]@^J]=^3]-^I^D^S]S^E]H]<g>]G]C_%]%_A_W]W_A_L_@_W]W_ J]0]S[3]0]P]5]4],b ="
3750  "[ThT[ R]T]!] M[T\\P]U[ R] ]L]6\\U\\ *]T].]P[S\\B]J]A]P[S\\N].^J]B^J]B^J]B^J]B^J]B^K^A]M]=]"
3751  "/].].].].].].].]-]G^F]N]W]B]G]D]G]D]G]D]G]D]G]?_T_AbK]E]I^C]I^C]I^C]I^;]6j;]K]A]M^?]M^?]M^"
3752  "?]M^?]M^?]M^?]M_?].].].].].].].].]/]J]@]L]@^L]@^L]@^L]@^L]@^L] J^X]Q]?]L]?]L]?]L]?]L];]W]8"
3753  "^M^<]W] I]R]S]C]H]C]VZOZW]C]VZL]C]H]@\\-]W] MuC]X[ ;cWZWbDeWZXe>e6e>]L]?]L]=]P]8^X^:] "
3754  " F^ H\\R\\5[S]5]Q]R]O^L` K]*] 0] !^.]L]6]4_\"]2],^>^M]8]6]J]0] DeCuCe E]R\\M]T\\P]I]A]J]@"
3755  "]/]G]D].]-]F]F]H]C].].]P^<].]Q_Q]H]N^X]B]G]E]-]G]E]L^.]8]5]J]<]W]6^X]O]X^J^Q^6]5^0]+^-] "
3756  "R]M^>^M]?].]M^?]-]/]M^?]L]?].].]U_8].]M]M]N]L]?]L]?^M]?]M^?] ]<].]M^<^W^6aRbB^V^6]W]7^(]4]"
3757  "(] GcUcE]P_=]L]A]P]9]L]@]-]L]:^X]9^P]<]M^@]P^O]I]T]T]?]P]>]S]S]@^L]@]L]8]5]M]?]I]>^2],]I]"
3758  "B_U]U_D]H]:c<]G]B_&]&_?_X]X_?_N_>_X]X_ I]0]S[3]0_T_5]4]+` ;[SfU[ P^U^#] L[U\\P]V[ Q] ]M^"
3759  "6\\U\\ ,^U^-\\P\\S\\B\\J]@\\P\\S\\N].]I]B]I]B]I]B]I]B]I]B]I]B^M]=]/].].].].].].].]-]G]E]N^X]B]G]D"
3760  "]G]D]G]D]G]D]G]@_R_A`J]D]J]A]J]A]J]A]J]:]6g8]K]A]M^?]M^?]M^?]M^?]M^?]M^?]M_?].].].].].].]."
3761  "].].]L]?]L]?]L]?]L]?]L]?]L]?]L]3^;aP]?]M^?]M^?]M^?]M^;]W]8^M];]W] H]S]T^B]J^B]J^B]J^B]J^@"
3762  "\\-]W] G^1_ :aW[V`BcW[Wc<d5c=]L]>]N]<]P]7]X]8] F]KZ X]S]5[S]5\\P]R]N]K_ K]*] 0] !]"
3763  ",]N]5]5_\"]1],]<]M]9^6^L^0] Ad Nd A\\R]O^U\\P^I^B]K^?]H[C]H^D].],]G]F]H]C].].]O^=].]P^Q]H]M]"
3764  "X]A]I]D],]I^E]K]AZH^8]5]J]<]W]5bObJ^O^7]6_0]*]-] R]M^>^M]?^/]M^?^.]/]M^?]L]?].].]T_9].]M"
3765  "]M]N]L]?]L]?^M]?]M^?] ]<].]M^;]W]5aRaB^U^6c8_(]4](] FaSaD]P_=]M]@]P]9]L]@]-]L]9b9]O^=^N^?"
3766  "\\P_Q]H]T]T]?]P]=]T]T]?^L]@]L]8]4]N]@^I^?]1],^K^A`W]W`C]H]7]8]I]@^&]&^=i=^N^<i H]0^T[3]1l6]"
3767  "4])_ <\\RbT\\ O]T]#] L\\V\\O]X\\ M^N^6\\U\\ ,]T]-\\OhF\\J]@\\OhQ]/^I^D^I^D^I^D^I^D^I^C]I]B]L]<"
3768  "]H[C].].].].].].].]-]H]D]M]X]A]I]B]I]B]I]B]I]B]I]@_P_B_J]C]J]A]J]A]J]A]J]:]6].]K]A]M^?]M^?"
3769  "]M^?]M^?]M^?]M^?]M_?^/^/^/^/^/].].].].]L]?]L]?]L]?]L]?]L]?]L]?]L]3^;`O]?]M^?]M^?]M^?]M^;c8"
3770  "^M];c G^U]U^@^M^@^M^@^M^@^M^?\\-c H^0_ 9^U[U^@aV[Va:b3a<]L]>^P^=^P]7]X]8_ H^M[ F] 6"
3771  "]S]>ZQ[T^6]P]S^N^K^ K]*] 0]:] 8]0],]O^5]6_2ZI]1]-^<^O^9]4]L]0]<].] Uc Pc1]2\\Q^S`W^P]G]B]K]"
3772  ">^J\\C]I^C].],^H]F]H]C].].]N^>].]C]H]MbA^K^D],^K^D]K^B[I]7]5^L^<c5aMaJ^N]7]6^/]*]-] R^O_>"
3773  "_O]=].]O_>].].]O_?]L]?].].]S_:].]M]M]N]L]>]N]>_O]=]O_?] ]<]-]O_;]X^5aRaC^S^6a8_']4](] D]P"
3774  "^B^Ra>^N]@]Q]7]N]?^.]L]9a8]N]=^N^?]Q_Q]G]U]U]>]P]=]T]T]?_N]>]N]7]4^P^@]G]@^1]+^M^?mB]H]7]8"
3775  "^K^?\\%]%\\;g;\\L\\:g G]/]T[3]2n7]4]'^ <\\F\\ M\\S\\ J\\F\\ L^N^6\\U\\ ,\\S\\-]OhG]K]@]OhQ]LZ=]G]"
3776  "D]G]D]G]D]G]D]G]D]G]D^L]<^J\\C].].].].].].].]-]J_D]MbA^K^B^K^B^K^B^K^B^K^A_N_B^K]B^L^A^L^A^"
3777  "L^A^L^:]6].]K]A^O_?^O_?^O_?^O_?^O_?^O_?^Oa?].].].].]/].].].]-]N]>]L]>]N]=]N]=]N]=]N]=]N]2^"
3778  ";_O]=]O_>]O_>]O_>]O_:a7_O]9a E^P_>^P_>^P_>^P_>^P_>\\,a H^.] /[5]T[S\\8a1`<]L]=^R^<]O^8b7_ "
3779  " H^O\\ F] 6\\R\\=[R[U^5\\N]T]L^M` L]*] 0]:] 8]1^+]P]4]7_1[L_1]<ZL^:^Q^8]4^N^>ZM];].] R` P"
3780  "`.]2]QfXaN]G]B]L^=^L]C]K_B].]+_J]F]H]C].].]M^?].]C]H]La@^M^C]+^M^C]J]B]L^7]4^N^:a4aMaK^M^8"
3781  "]7^.]*^.] Q]P`>`Q^=^NZ;^Q`>_LZ>].^Q`?]L]?].].]Q^;].]M]M]N]L]>^P^>`Q^=^Q`?]/ZL];]-^Q`:a4`"
3782  "P`D^Q^7a8^&]4](] S]Sb>_P^@]R^7^P^>^MZ<]L]9a9]M]=_P`XZB]Q_Q]G^V]V^>]P]=^U]U^?`P^>^P^6]4]Q"
3783  "^?]G]A^0]*^O^<i@]H]7]7^M^=Z$]%Z8e9ZKZ7e F]/^U[TZ9]3^V`V^8]4]&^ <\\H\\ K[R[ I\\H\\ K_P`XZ9"
3784  "\\U\\ ,[R[,\\E\\D\\K]?\\E\\M]O\\=]G]D]G]D]G]D]G]D]G]D]G]D]K];^L]C].].].].].].].]-]K_C]La@^M^@^M^"
3785  "@^M^@^M^@^M^A_L_C`N^A^N^?^N^?^N^?^N^9]6].]L]?]P`>]P`>]P`>]P`>]P`>]P`>]P]X^LZN^NZ;_LZ>_LZ>_"
3786  "LZ>_LZ?].].].]-^P^>]L]>^P^=^P^=^P^=^P^=^P^2^:^P^=^Q`>^Q`>^Q`>^Q`:a7`Q^9a Dk<k<k<k<k>],a "
3787  "H]-] /[,[._0_;]L]=j<]N]7`5a J_S^ F] 6\\R\\=^U[W_5]N^V^K_Rd L],] /]:] 8]1])^T^3]8_0^Q`0"
3788  "]<]Q_8^S^8^3_R_=]R^:].] O] P]+]1\\PdW`N^G^C]N_;`R`C]NaA].]*`O`F]H]C].].]L^@].]C]H]La?`S`B]*"
3789  "`S`B]J]B`Q_6]3_R_9a4aMaL^K^9]8^-])].] Q_Tb>aS^;_R\\:^Sa=`Q]>]-^Sa?]L]?].].]P^<].]M]M]N]L]"
3790  "=_T_=aS^;^Sa?]/^R_:]-^Sa:a3_P_C^P^7_8^%]4](] S_V^X^?aS^>]T^5_T_=`R]<]L]8_8]M^>`SdA]SaS]E"
3791  "^W]W^=]P^=_W]W_>]X]T_<_T_5^4^T^?^G^C^/])^Q^8c=]H]7]6`S` ?] ;c >c E]._W[V\\9]4^J^9]4]%] ;]L]"
3792  " IZQZ H]L] !u ,`Sd9\\U\\ ,ZQZ,]E\\E]L]?]E\\M_S^>^G^F^G^F^G^F^G^F^G^F^G^F^K]:`R`C].].].].]."
3793  "].].]-]ObB]La?`S`>`S`>`S`>`S`>`S`?]J]CcS`?_R_=_R_=_R_=_R_8]6].]V[R^?_Tb>_Tb>_Tb>_Tb>_Tb>_T"
3794  "b>_T^V_Q]M_R\\:`Q]=`Q]=`Q]=`Q]?].].].],_T_=]L]=_T_;_T_;_T_;_T_;_T_1^:`T_;^Sa=^Sa=^Sa=^Sa9_6"
3795  "aS^7_ Bi:i:i:i:i=]+` I],] /[,[-].]:]L]<h;]N]7`3q \"h E] 7]S]=k5]LdIjW^ M],] /]:] 8]1"
3796  "](f9k?n?l/]<j6g7]1j<h9].] LZ PZ(]1]O`U]K]E]Cm8kBn?n?](nE]H]C].].]K^Am>]C]H]K`>kA])kA]J^Cm5"
3797  "]2j7_2`M`K^J]9]8tC])].] PgX]>]Xf9h9fX]<k>],fX]?]L]?].].]O^=].]M]M]N]L]<h<]Xf9fX]?]/j9d4g"
3798  "X]:a3_P_D^O^7_8m4]4](] RfXaBk=^V^3h;j<]L]8_9^L]>qA^U]W]U^Di<]O`?k=]Xg:h3a7f>uCn?]/eSe;]:"
3799  "]H]7]5k >] :a <a D]-h>n?\\H\\8]4]%] 9^R^ *^R^ Xu ,q9\\U\\ /]D\\F]LfH]D\\Li>]E]F]E]F]E]F]E"
3800  "]F]E]F]E]F]JnIkBn?n?n?n?].].].]-n@]K`>k<k<k<k<k=[H[Co<j;j;j;j7]6].]Vf=gX]=gX]=gX]=gX]=gX]="
3801  "gX]=gTjLh9k<k<k<k?].].].]+h<]L]<h9h9h9h9h Fk:gX]=gX]=gX]=gX]9_6]Xf6_ @e6e6e6e6e;]+_ G\\+["
3802  " /].]-[,[9]L];e:^N^8`2p e D] 7]S]<i4\\JbGgT^ M\\,\\ .]:] 8]1]'d8k?n>i-]<i4e6]0h;g8].] "
3803  " I]0]3]E]Cl6h@l=n?]&jC]H]C].].]J^Bm>]C]H]K`<g?]'g?]I]Bj3]1h6_2_K_L^I^:]8tC])].] OdV]>]Wd"
3804  "6f8dW]:i>]+dW]?]L]?].].]N^>].]M]M]N]L];f;]Wd7dW]?]/i7c3dV]9_2_P_E^M^8_8m4]4](] QdV`B]Xe;"
3805  "d1f8h<]L]8_9]K]>]XdW_@eWeBg;]O`=g;]Vd8f1`6d=uCn?]/eSe;]:]H]7]3g <] 9_ :_ C]+f>n>ZFZ7]4]%] "
3806  "7f &f Vu ,]XdW_9\\U\\ /\\C\\F\\KfH\\C\\Kg=]E]F]E]F]E]F]E]F]E]F]E]F]JnHh@n?n?n?n?].].].]-l>"
3807  "]K`<g8g8g8g8g J]Vh:h9h9h9h6]6].]Ve;dV]<dV]<dV]<dV]<dV]<dV]<eRiJf7i:i:i:i?].].].]*f;]L];f7f"
3808  "7f7f7f F]Xe7dV]<dV]<dV]<dV]9_6]Wd5_ <\\-\\-\\-\\-\\6]+_ FZ*[ /].],Z+Z9]L]8`8]L]7^.m W` "
3809  "A] 7\\R\\7b2]H^BaP_ O].] .]:\\ 7]2^%`6k?n:b*]9c/a5],b6b5].\\ H]/\\4]C]Di0b=h9n?]#c?]H]C].].]I"
3810  "_Dm>]C]H]J_9a<]$d?]I^?c0].b3_2_K_M^G^;]8tC](]/] M`T]>]U`2b4`U]7c;])`U]?]L]?].].]M^?].]M]"
3811  "M]N]L]8`8]U`3`U]?],c2a0_T]9_2^N^F^K^8]7m4]4](] O`R^B]Va8b-`3d:]L]7]9^J]?]V`T]>cUc?c9]N_:"
3812  "a8]T`3`-_4`<wDn?]/eSe;]:]H]7]0a 9] 8] 8] B])b<n @]4]&^ 5b \"b Tu ,]V`T]8\\U\\ 0].].]0b"
3813  ";]C]H]C]H]C]H]C]H]C]H^E^H^JnEb=n?n?n?n?].].].]-h:]J_9a2a2a2a2a G\\Rb4b3b3b3b3]6].]Vc7`T]:`T"
3814  "]:`T]:`T]:`T]:`T]:aMcEb2c4c4c4c<].].].]'`8]L]8`1`1`1`1` D]Ua2_T]9_T]9_T]9_T]8]5]U`2] "
3815  "=] &[ O].] E] E] '] S] R] ^ (](]/] "
3816  " C] S] '] V] F^ 7]4](] %])[ 4]7] @])_Q_:] 9]6] 6[ S]0[R"
3817  "^ H]%\\U\\ A\\ @\\ /Z <\\ ,[ M^5](^ "
3818  " =] &[ N]0] D\\ D] '\\ Q^DZ 1] _ )"
3819  "](]/] D^ S] '] V] F] 6]4](] %] ;]7] @] /] 9]6] 6[ S]0"
3820  "g H]%\\U\\ @\\ @\\ J\\ X]4](] "
3821  " <] &[ N]0] D\\ E^ '\\ P^G] 2] X^ )]"
3822  "(^0] D] R] '] V] G^ 6]4](] %] ;]7] @] /] 9]6] 6[ S]0e"
3823  " F]%\\U\\ ?[ ?[ I[ ^4])^ "
3824  " @ZV] &[ M]2] D] E] '] O_K_ 3] V^ *b"
3825  ",]5b E^ R] '] V] G^ 6^5])^ %] ;]7] @] /] 9]6] 6[ S].a"
3826  " D]%\\U\\ ?\\ @\\ J\\ !^4])^ "
3827  " B\\V] &[ M]2] D\\ G\\ L`P` 2] U^ +b "
3828  "=b RZN^ R^ '] V] H^ 4^6]*^ $] ;]7] @] /] 9]6] 6[ S] "
3829  " J] :\\ @\\ J\\ \"^3]*^ A\\V"
3830  "\\ %[ L]4] Vm 2^ S^ ,b =b "
3831  " R\\Q_ R] &] V] I^ 3b:].b $] ;]7] @] /] 9]6] 6[ S] "
3832  " J] @ZU] FZU] PZU] #^2]+^ @b "
3833  " %[ Si 4b %i Ua &]"
3834  " V] Mb 2a:].a #] ;]7] @] /] 9]6] .] J] @b "
3835  " Fb Pb 'b2] E` "
3836  " Qb 1a $g S` %] V] Ma /_:]._ !] "
3837  " ;]7] @] /] 9]6] .] J] @a Ea "
3838  " Oa &a1] D^ "
3839  " X^ Ip Fc Q^ #] V] M_ A] )] ;]7] @] /] 9]6] "
3840  " T] @` D` N` %_/"
3841  "] BZ Ap "
3842  " 6] "
3843  " "
3844  " p 6] "
3845  " "
3846  " "
3847  " F]']2] +]']2^ D]']3_ E]']1] \"]']2^ "
3848  "8] H";
3849 
3850  // Define a 90x103 font (huge size).
3851  static const char *const _data_font90x103[] = {
3852  // Defined as an array to avoid MS compiler limit about constant string (65Kb).
3853  // First string:
3854  " "
3855  " "
3856  " "
3857  " "
3858  " HX 4V >X IX *W FW "
3859  " "
3860  " "
3861  " "
3862  " "
3863  " HX W 4Z 3VCT <Z >X W 4Z "
3864  " HX W 4Z 'VCT ;X W 3Y 2UCT KX W 3Y 0W "
3865  " "
3866  " "
3867  " "
3868  " "
3869  " @W !W 4\\ 5YET ?XHX 8] >W !W 4\\ 7XGX KW !W 4\\ 7XHX "
3870  " +YET :W !W 3[ 5ZFT ?XGX EW !W 3[ 7XGX 5W "
3871  " "
3872  " "
3873  " "
3874  " "
3875  " >W \"V 3\\ 7]HU ?XHX 9` ?W \"V 3\\ 7XGX JW \"V 3\\ 7XHX -]HU"
3876  " 9W \"V 3] 7]HT ?XGX DW \"V 3] 8XGX 5V "
3877  " "
3878  " "
3879  " "
3880  " "
3881  " <W $V 3VNV 8_KV ?XHX 9` >W $V 3VNV 8XGX IW $V 3VNV 8XHX -_KV"
3882  " 8W $V 2] 7_KU ?XGX CW $V 2] 8XGX 6V "
3883  " "
3884  " "
3885  " "
3886  " "
3887  " :W &W 4VLV :j >XHX :VJV >W &W 4VLV 9XGX HW &W 4VLV 9XHX .j 6"
3888  "W &W 3VMV 9i >XGX BW &W 3VMV 9XGX 7W MW "
3889  " "
3890  " "
3891  " "
3892  " "
3893  " CV 'W 4VJV ;j >XHX ;UGV >V 'W 4VJV :XGX GV 'W 4VJV :XHX .j"
3894  " 5V 'W 3VKV :i >XGX AV 'W 3VKV :XGX 8W N[ "
3895  " "
3896  " "
3897  " "
3898  " "
3899  " DV )W 4VHU <VK_ =XHX ;TEU =V )W 4VHU :XGX FV )W 4VHU :XHX "
3900  " /VK_ 3V )W 3VIV <UK_ =XGX @V )W 3VIV ;XGX 9W N] "
3901  " "
3902  " "
3903  " "
3904  " "
3905  " DV *V 3UFU =UH\\ <XHX <UDT <V *V 3UFU ;XGX EV *V 3U"
3906  "FU ;XHX /UH\\ 1V *V 2UGU <TH] =XGX ?V *V 2UGU ;XGX 9V a "
3907  " "
3908  " "
3909  " "
3910  " "
3911  " EV ,V 3UDU >TEY ;XHX <TBT <V ,V 3UDU <XGX D"
3912  "V ,V 3UDU <XHX /TEY /V ,V 2UEU =TFZ <XGX >V ,V 2UEU <XGX :V Na "
3913  " "
3914  " "
3915  " "
3916  " "
3917  " DU -V 3VDV ?TCV :XHX <TBT ;U -V 3VD"
3918  "V =XGX CU -V 3VDV =XHX /TCV -U -V 2UCU >TCU :XGX =U -V 2UCU =XGX ;V NV"
3919  "IV \"W "
3920  " "
3921  " "
3922  " "
3923  " JU /V 3VBV ETBT :U /"
3924  "V 3VBV FU /V 3VBV (U /V 2UAU DU /V 2UAU @V NVGV "
3925  " $X "
3926  " "
3927  " *X "
3928  " "
3929  " JX GTBT "
3930  " MX GX 7V :UEU DX GX 7V JX GX 7W 4X GX 6V "
3931  " GX GX 5V (X &X "
3932  " "
3933  " )X 8V "
3934  " "
3935  " ;X FTBT "
3936  " LX IX 7X <UCU DX IX 7X JX IX 6W 3X IX 6X GX IX 5X "
3937  " *X &Y "
3938  " "
3939  " (X 9V "
3940  " <X "
3941  " ETBT KX "
3942  "KX 6X 1TBT BTAT CX KX 6Y JX KX 6Y (TBT BX KX 5X 1TBT LX KX 4X +X "
3943  " %T #W 9W "
3944  " "
3945  "3a :a <W 2W >W E\\ AW ,W ,W ,W ,W HY GV +Y "
3946  " 4Z NX @X "
3947  " %W DUDU "
3948  " =Y 7W KW 6Z 4XDT BTAT BW KW 6Z IW KW 6[ ,Y )XDT AW KW 5Z 4XDT "
3949  " KW KW 4Z ,W BW 8V (S "
3950  " <S 9V 7V "
3951  " 3a :a ;W 3W >W H_ AW ,W ,W ,W ,W "
3952  " L] GV +] ;a #[ F^ "
3953  " 8XGX +W BTEU "
3954  " *R 9a :W MW 6\\ 6ZET ?XHX <TAT AW MW 6\\ 7XGX LW MW "
3955  "5[ 7XGX .Y +ZET @W MW 5\\ 6ZET ?XHX DW MW 4\\ 7XHX 0W AW &XHX MZ "
3956  " +T $Y BS 1W,V MY 8W 7W T 9X 5Z /"
3957  "[ 0Z 8Z /Y GY .\\ <\\ [ 4[ :\\ -a "
3958  " :a :W 4W >W Ja AW ,W ,W ,W ,W N_ GV +_ "
3959  "?e 8] J] Jb 8[ <[ $Y FY 7XGX "
3960  "=Z Di 5W 8Z .Y !W FW *Y 4W)V*W)V-Y(V <UFU 3\\ "
3961  " +[ 0[ 0[ 0[ 0[ 4[=T <e ;W W 5\\ 7\\FT ?XHX <TAT @W W 6^ 8XGX KW W"
3962  " 5] 8XGX .Z@R ?\\FT ?W W 4\\ 7\\FT ?XHX CW W 3\\ 7XHX 1W @W &XHX N\\ "
3963  " ,T :U :U5U ` EX 2VFV .S 4]0W\"b DV V 5V T 7W"
3964  " .` 3[ 7c 8d )Z Dq 8b Hy Bb 7` Na /Z @k .d Kj ?x Mt 7f MX/X'X -X -X2Z&X -]0]0["
3965  "3X Dc Ii -c Ij 4f N~W$X/X.X&X.X4Y4XDY/Y/Y,Y'~S%a >W $a MY EW 5W >W Kb AW ,W ,W"
3966  " ,W ,W !a GV +a Ch =f ^ Mf 2Z @"
3967  "x Mx <c 3X C~Q)X?X?X Kc 2T .V .T CX $a !W.W N` ;XGX ![ Lb &Z Mi 7[ >a"
3968  " 5a &W 0g #\\ -_ <\\*V.\\*V0a-V\"X )Z /Z /Z /Z /Z 4WJV 1~U+d Kx Mx Mx Mx MX -X -X -X ,j"
3969  " @[3X Dc 8c 8c 8c 8c <cBV.X/X'X/X'X/X'X/X/Y,Y$X &h ;W \"W 5VNV 8]HU ?XHX <TAT ?W \"W 5"
3970  "VNV 8XGX JW \"W 5VMV 9XGX -ZDV @]HU >W \"W 4VNV 8]HU ?XHX BW \"W 3VNV 8XHX 2W ?W &XHX "
3971  " ^ K~\\ >S 3Q +[ @[;[ ;Q ;e HX 2VFV #VBV FS 6`"
3972  "1V#g GV !V 3V !T 7W 0d :` ;j ?k -[ Dq :g Ky Df ;d $f 1Z @o 5j Np Ex Mt "
3973  ":m\"X/X'X -X -X3Z%X -]0]0\\4X Gi Lm 4i Ln ;m#~W$X/X-X(X-X4Y4XCY1Y-Y.Y&~S%a >W $a N[ EV "
3974  "5W >W Lc AW ,W ,W ,W ,W \"b GV +a Dk Aj \"_"
3975  " h 3Z @x Mx ?i 6X C~Q)X?X?X Ni 6V /V /V DX &f #W0W e >XGX %c#"
3976  "e +b\"i 9_ Be 9d 'V 3k %^ /c @^*V0^*V2d.V\"X )Z /Z /Z /Z /Z 3b 1~U.j Nx Mx Mx"
3977  " Mx MX -X -X -X ,p F\\4X Gi >i >i >i >i BiEV.X/X'X/X'X/X'X/X.Y.Y#X 'j ;V \"V 5VLV :_IT >XH"
3978  "X <TAT >V \"V 5VLV 9XGX IV \"V 4VMV 9XGX ,ZHY A_IT <V \"V 4VLV :_IT >XHX AV \"V 3VLV 9"
3979  "XHX 2V >W &XHX !_ K~[ >T 4R -_ D_?_ >S =t Fh "
3980  " IX 2VFV #VBV FS 7c4V#i HV \"W 3V !T 7V 0f @e >o Co 0\\ Dq <j Ly Fj ?h (i "
3981  "\\ ?Z @r :o\"s Hx Mt <q$X/X'X -X -X4Z$X -]0]0\\4X Im Np 9m Np ?q%~W$X/X-X(X,W5[6XAX1X+X.X%~S%"
3982  "a =V $a ] EV 6W >W Md AW ,W ,W ,W ,W HW 1b GV +b "
3983  " Fm Dm #` \"j 4Z @x Mx Am 8X C~Q)X?X?X!m 9X 0V 0X EX 'h"
3984  " $W0W \"h ?XGX 'g%g 0h%i :a Cf :f *V 4m %^ 0e A^+V/^+V1f1V!X )Z /Z /Z /Z /"
3985  "Z 2` 1~V0o\"x Mx Mx Mx MX -X -X -X ,t J\\4X Im Bm Bm Bm Bm FmHV-X/X'X/X'X/X'X/X-X.X\"X (l ;"
3986  "V $V 4UJU :ULXLU >XHX <UCU =V $V 5VJV :XGX HV $V 4VKV :XGX +ZL\\ AULXLU ;V $V 3UJU :ULX"
3987  "LU >XHX @V $V 2UJU 9XHX 3V =W &XHX !` K~Z >T 4S /a FaAa @T "
3988  " @w Hl KX 2VFV $WCV ES 8e5V$j HV \"V 1V \"T 7V 2j Eh ?q Dp 1\\ Dq >"
3989  "l Ly Hn Bj +l %e E\\ At >s$v Kx Mt >u&X/X'X -X -X5Z#X -^2^0]5X Jo q ;o r Br%~W$X/X"
3990  "-X(X,X6[6XAY3Y+Y0Y%~S%W 3V IW !_ FW 7W >W Md AW ,W ,W ,W ,W HW "
3991  " 2[ ?V #[ Hn En #` #l 6\\ Ax Mx Cp 9X C~Q)X?X?X\"o "
3992  " ;Z 1V 1Z FX KS 0i #W2W LV ,i ?XGX *l'h 3l'i ;c Dg ;g ,W 6o %^ 1g B"
3993  "^,V.^,V0g3V X *\\ 1\\ 1\\ 1\\ 1\\ 2^ 0~V2s$x Mx Mx Mx MX -X -X -X ,v L]5X Jo Do Do Do Do HpKW"
3994  "-X/X'X/X'X/X'X/X-Y0Y\"X )n <W &W 5VJV ;TI_ >XHX ;UEU <W &W 5VIV ;XGX HW &W 5VIV ;XGX *g"
3995  " ?TI_ ;W &W 4VJV ;TI_ >XHX @W &W 3VJV :XHX 4W =W &XHX 1\\ 1\\ 1\\ 1\\ 1\\ =XMV K~Y "
3996  " =S 4U 1c IdCc AU Dz In LX 2VFV $VBV ES 9g7V$k HV #W 1W #T "
3997  " 8W 3l Fh ?r Eq 3] Dq ?m Ly Ip Em -n )k H\\ Au Av%x Mx Mt ?x(X/X'X -X -X6Z\"X -"
3998  "^2^0]5X Ls\"s ?s\"s Et%~W$X/X,X*X+X6[6X@Y5Y)Y2Y$~S%W 3W JW \"a FW 8W >W NZ 6W ,W "
3999  ",W ,W ,W HW 2X <V X H[G[ Go KZ %"
4000  "[H[ 7\\ Ax Mx Ds ;X C~Q)X?X?X$s >\\ 2V 2\\ GX KS 1j #W2W LV -j ?XGX +ZEZ)VGY "
4001  "5ZDZ)i <e EUFY <UFX -W 7q %VMU 2YIY CVMU,V.VMU,V0UFX3V X *\\ 1\\ 1\\ 1\\ 1\\ 1\\ 0~W4v%"
4002  "x Mx Mx Mx MX -X -X -X ,x N]5X Ls Hs Hs Hs Hs LsMW,X/X'X/X'X/X'X/X,Y2Y!X *\\G[ <W (W 4UHU"
4003  " <UH] =XHX ;VGV ;W (W 5VHV ;XGX GW (W 4UGU ;XGX )c =UH] 9W (W 3UHU <UH] =XHX ?W (W"
4004  " 2UHU :XHX 5W <W &XHX 5c 8c 8c 8c 8c @WKU J~X >T 5V 2e KfEe CW G| "
4005  " Jp MX 2VFV $VBV ES 9XIX8V$l HV #V /V #T 8V 3n Gh ?s Fr 5^ Dq @n Lx Ir"
4006  " Go .o -q L^ Bv Cx&z x Mt A{)X/X'X -X -X7Z!X -^2^0^6X Mu#t Au#t Gu%~W$X/X,X*X+X6["
4007  "6X?X5X'X2X#~S%W 2V JW #c FW 9W >W NX 4W ,W ,W ,W ,W HW "
4008  " 2W ;V NW IZCY Hp JY &ZDZ 9^ Bx Mx Eu <X C~Q)X?X?X%u @"
4009  "^ 3V 3^ HX KS 2k \"W4W KV -ZGW ?XGX -X=X+R@W 8X<X .XIX FQ@W <Q@W /W 7dGU"
4010  " %QHU 3XEX DQHU-V-QHU-V/Q@W5V NX +^ 3^ 3^ 3^ 3^ 2\\ 0~W5x&x Mx Mx Mx MX -X -X -X ,z!^6"
4011  "X Mu Ju Ju Ju Ju N}+X/X'X/X'X/X'X/X+X2X X +ZBY ;W *W 4UFU =TF\\ =XHX :VIV 9W *W 5VFV "
4012  "<XGX FW *W 4VGV <XGX (_ :TF\\ 8W *W 3UFU =TF\\ =XHX >W *W 2UFU ;XHX 6W ;W &XHX 7h =h"
4013  " =h =h =h DWJV K~X >T 5W 4g MgFg EY J~ K]FZ MX 2VFV $VBV "
4014  "ES :XGX9V%\\GX HV $W /W 3PATAP GV 3[H[ Gh ?]F] GZE^ 6^ Dq A]FX Lx I\\F\\ G\\G[ "
4015  " /[H] 0u N^ Bw E_D^&{!x Mt B`C_)X/X'X -X -X8Z X -_4_0_7X N^E^$u C^E^$u H^E\\%~W$X/X,Y,Y*W7"
4016  "]8X>Y7Y'Y4Y#~S%W 2V JW $e FV 9W >W NW 3W ,W ,W ,W ,W HW "
4017  " 2W ;V NW IY@X >X 4[AV IX &X@X 9^ Bx Mx F^E^ =X C~Q)X?X?X"
4018  "&^E^ B` 4V 4` IX KS 3\\GW \"W4W KV .YBT ?XGX .V7V,P=W :W8W /VEV 3V +V /V "
4019  " 7eGU KU 3WCW ;U-V$U-V LV5V NX +^ 3^ 3^ 3^ 3^ 3^ 1~W6_D^&x Mx Mx Mx MX -X -X -X ,{\""
4020  "_7X N^E^ L^E^ L^E^ L^E^ L^E^ !^Ed*X/X'X/X'X/X'X/X+Y4Y X +Y?X ;V *V 4UDU >TEZ <XHX 9a "
4021  "7V *V 4UDV =XGX EV *V 4VEV =XGX )] 7TEZ 6V *V 3UDU >TEZ <XHX =V *V 2UDU <XHX 6V :W &XH"
4022  "X 9k @k @k @k @k EWJV K~W >T 5Y 5g MhHi G[ M~Q L\\AW M"
4023  "X 2VFV $VCV DS :WEW:V%ZAU HV $V -V 3RCTCR HW 4ZDZ H\\LX ?Y?[ HV>\\ 8_ DX )[?T -Y J[B"
4024  "[ I[CZ 0WAZ 2x ^ BX>^ G]=Z&X=b#X -X '];[)X/X'X -X -X:[ NX -_4_0_7X \\?\\%X@^ E\\?\\%X"
4025  "?] J[=X =X <X/X+X,X)X8]8X=Y9Y%Y6Y )Y$W 2W KW %ZMZ FV :W >W X 3W 4W ,W "
4026  " HW 3X ;V NX KY?X Ca 9Y:R HX (X>X :VNV "
4027  "BZ /X '\\?\\ A^ FX0X)X?X?X'\\?\\ Db 5V 5b JX KS 3ZBT !W6W JV .X?R 4V4U HV ;V"
4028  "4V 1VCV 4V *U 0V 7fGU KU 4WAW <U.V#U.V JU6V MX +^ 3^ 3^ 3^ 3^ 3^ 2XIX F]=Z&X -X"
4029  " -X -X -X -X -X -X ,X=b$_7X \\?\\ N\\?\\ N\\?\\ N\\?\\ N\\?\\ #\\?`)X/X'X/X'X/X'X/X*Y6Y NX ,Y=W :V ,"
4030  "V 3UDU >TDX ;a 6V ,V 4UBU GV ,V 3UCU 0` 6TDX 4V ,V 2UDU >TDX >V ,V 1UDU "
4031  ":V 9W (o Do Do Do Do GWIU J~V >T 6Z 6i jIj I\\ N~R M[="
4032  "U MX 2VFV %VBV H] AWCW;V%Y=R HV %W -V 4UETEU IV 4ZBZ IWGX ?V;[ IS9Z 9VNX DX *Z;R"
4033  " -X JZ>Y JZ?Y 1U>Z 5`C_#` CX;[ H[7W&X9_$X -X (\\6X)X/X'X -X -X;[ MX -_4_0`8X![;[&X"
4034  "=[ F[;[&X<[ LZ8U =X <X/X+X,X)X8]8X<X9X#X6X )Z$W 1V KW &ZKZ FV ;W >W W 2W 4"
4035  "W ,W HW 3W :V MW KX=W Cc ;X7P HX ("
4036  "W<W ;WNW BY /X ([;[ Gg JX0X)X?X?X([;[ Fd 6V 6d KX KS 4Y>R !X8X JV /X<P 6V1U IV"
4037  " <U0U 2UAU 3U *U 1V 6fGU KU 4V?V <U/V\"U/V IU7V LX ,` 5` 5` 5` 5` 5` 3XIX "
4038  "G[7W&X -X -X -X -X -X -X -X ,X9_%`8X![;[![;[![;[![;[![;[ %[;](X/X'X/X'X/X'X/X)X6X MX ,X;W"
4039  " :V .V 3UBU ?TBT 7] 3V .V 4VAU GV .V 3UAU 4d 7TBT 1V .V 2UBU ?TBT ;V .V 1U"
4040  "BU <V 8W )r Gr Gr Gr Gr IVHR GX+W =S 5[ 7i!kJk I] !^ "
4041  " )Y:T MX 2VFV %VBV Le EVAV<V$X:P HV %W -W 6WFTFV IV 4X?Y IRBX ?T7Y IP5Z :VNX DX "
4042  "+Z8P .Y JY<Y KY=X 1S;Y 6];\\$WNW CX9Z J[4U&X6]%X -X )[2V)X/X'X -X -X<[ LX -XNV6VNX"
4043  "0`8X\"Z7Z'X;Z HZ7Z'X;Z LY4R =X <X/X*X.X(X8]8X<Y;Y#Y8Y *Z#W 1V KW 'ZIZ FV <W >W W "
4044  " 2W 4W ,W HW 3W :V MW KW<X Dd <W -W "
4045  " )W;X <WNW AY 0X )Z7Z Jl MX0X)X?X?X)Z7Z Hf 7V 7f LX KS 4X;P W8W IV /W \""
4046  "V.U JV >U.U 4VAV &V 5U *U 2V 6gGU KU 5W?W =U/V\"U/V IU7V LX ,WNW 5WNW 5WNW 5"
4047  "WNW 5WNW 5WNW 4XHX H[4U&X -X -X -X -X -X -X -X ,X6]&`8X\"Z7Z#Z7Z#Z7Z#Z7Z#Z7Z 'Z8['X/X'X/X'"
4048  "X/X'X/X)Y8Y MX ,W:W 9V 0V 3U@U ?[ 1V 0V 3U@V GV 0V 3U?U 8h 1V 0V 2U@U "
4049  " CV 0V 1U@U >V 7W *`L` I`L` I`L` I`L` I`L` JV =X,X >T 6] 9k\"lKl K_ "
4050  " #\\ 'Y8S MX 2VFV %VBV Nk IVAV=V$X 1V %V +V 6YHTHY -V EW 5Y>Y :X ?R5"
4051  "Z .Y ;VMX DX +Y DX IY<Y LY;X 2Q8Y 8[5[&WNW CX8Y KZ1T&X4\\&X -X *Z.T)X/X'X -X -X=["
4052  " KX -XNV6VNX0a9X#Z5Z(X:Y IZ5Z(X:Z NY1P =X <X/X*X.X'W9WNV:X:Y=Y!Y:Y *Z\"W 1W LW (ZGZ -"
4053  "W >W W 2W 4W ,W HW 3W :V MW KW;W De =W "
4054  " -X *W:W <VLV @Y 1X *Z5Z Mp X0X)X?X?X*Z5Z Jh 8V 8h MX KS 5Y :X:X"
4055  " IV /W #U+T JV ?U+T 5U?U &V 5U +V AgGU KU 5V=V =U0V!U0V IV8V KX ,WNW 5W"
4056  "NW 5WNW 5WNW 5WNW 5WNW 4XHX IZ1T&X -X -X -X -X -X -X -X ,X4\\'a9X#Z5Z%Z5Z%Z5Z%Z5Z%Z5Z )Z5Z"
4057  "(X/X'X/X'X/X'X/X(Y:Y LX -X:W !W 2\\LZ "
4058  "EW +[@[ K[@[ K[@[ K[@[ K[@[ KV <X-X /P 0T 7^ 9k\"lLm La %Z "
4059  " %Z6Q MX 2VFV %VCV n KWAW>V$X 1V &W +W 5XITIX +V EV 4X<X :X ?P2Y -X <WMX DX ,Y C"
4060  "X JY:Y MX9W 2P7Y :Z0Z(WLW DX7X KY.R&X2Z&X -X *Y+R)X/X'X -X -X>[ JX -XNW8WNX0a9X#Y"
4061  "3Y(X9Y JY3Y(X9Y NX LX <X/X*X.X'X:VMV:X9X=X NX:X *Z!W 0V LW )ZEZ .W >W W 2W "
4062  " 4W ,W HW 3W :V MW LX;W Df >W ,W "
4063  " +W8W >WLW @Y 2X +Z3Z!t\"X0X)X?X?X*Y3Y Kj 9V 9j AS 5X 8W:W HV /W #T)T KV "
4064  " @T(T 6U?U &V 5T +V AhGU KU 5V=V =U0V!U0V JV7V WLW 7WLW 7WLW 7WLW 7WLW 7XNX "
4065  "6XGX IY.R&X -X -X -X -X -X -X -X ,X2Z'a9X#Y3Y%Y3Y%Y3Y%Y3Y%Y3Y )Y3Z)X/X'X/X'X/X'X/X'X:X Ki"
4066  " >W8V *XHZ FW ,Z<Z MZ<Z MZ<Z "
4067  "MZ<Z MZ<Z LV <X.X .R 2S 7` :k#nMm Mb &Z $Y4P MX 2VFV &VBV!o "
4068  "KV?V?V#W 0V &V )V 3XKTKX )V EV 5X:X ;X X -Y =VLX DX -Y CY JY:Y NY9X HX ;"
4069  "Z-Y)WLW DX7Y MY,Q&X1Z'X -X +Y)Q)X/X'X -X -X?[ IX -XMV8VMX0XNX:X$Y1Y)X9Y KY1Y)X8X NX LX <X"
4070  "/X)X0X&X:VMV:X9Y?Y NY<Y *Y W 0V LW *ZCZ /W >W W 2W 4W ,W HW"
4071  " 3W :V MW LW:W Dg ?W ,X ,W8W >WLW ?Y 3X +Y1Y\"v#X"
4072  "0X)X?X?X+Y1Y MYNVNY :V :YNVNY BS 5X 8X<X HV /W $T?ZBT*c AT&T 7U?U &V "
4073  "6U -W @hGU KU 6V;V >U1V U1V KW7V NWLW 7WLW 7WLW 7WLW 7WLW 7WLW 6XGX JY,Q&X -X "
4074  "-X -X -X -X -X -X ,X1Z(XNX:X$Y1Y'Y1Y'Y1Y'Y1Y'Y1Y P)P$Y3[)X/X'X/X'X/X'X/X'Y<Y Km BW8W "
4075  " +UDZ 7P 1W -Y8Y Y8Y Y8Y Y8Y Y8Y MV ;"
4076  "W.X /T 4T 7a ;k#nMn Nc 6P :W4W ?Z ?X6X KY #Y 0X 2VFV &VBV\"p KV?V?V#"
4077  "W 0V 'W )W 2XMTMX 'V FW 5X:X ;X Y -X >VKX DX -X BX IX8X NX7W KP 1P =X <Y)X+"
4078  "XLX EX6X NY*P&X0Z(X -X ,Y'P)X/X'X -X -X@Z GX -XMV8VMX0XNX:X%Y/Y*X8X LY/Y*X8Y!X KX <X/X)X0"
4079  "X&X:VMV:X8YAY LY>Y *Z W 0W MW +ZAZ 0W >W W 2W 4W ,W HW "
4080  " 3W :V MW LW:W DSF[ @X -X -X8W ?WJW ?Y 4X ,Y/Y%z%X0X)"
4081  "X?X?X,Y/Y YMVMY ;V ;YMVMY CS 5X 5P*Q JW<W GV /W %TBbET/g BTGb?T 8U?U &V"
4082  " 7U 5_ ?hGU KU 6V;V >U2V NU2V$_7V NXLX 9XLX 9XLX 9XLX 9XLX 8WLW 6XGX KY*P&X -X"
4083  " -X -X -X -X -X -X ,X0Z)XNX:X%Y/Y)Y/Y)Y/Y)Y/Y)Y/Y\"R+R&Y3]*X/X'X/X'X/X'X/X&Y>Y Jp EW:Y "
4084  " +R@Y 7Q 2W .XEVFY\"X5Y\"X5Y\"X5Y\"X5Y N"
4085  "V ;X/X 0V 5T 8c <k#nNo e >^ AW4W ?Z >W6W KY \"Y 0X 2VFV &VCW#[LSKZ K"
4086  "V?V@V\"W 0V 'W )W 1XNTNX &V FW 6Y:Y <X NX -X ?WKX DX .Y CY IX8X NX7W NS 1S @"
4087  "X =X&X,WJW EX6X NY /X/Y(X -X ,Y /X/X'X -X -XAZ FX -XMW:WMX0XMX;X%Y/Y*X8Y MY/Y*X8Y!X KX <X"
4088  "/X)Y1X%W;WMW;W6XAX JX>X *Z NW 0W MW ,Z?Z 1W >W W 2W 4W ,W H"
4089  "W 3W :V MW LW:W DPAY ?Y .W -W6W @WJW >Y 5X ,X-X&"
4090  "_MXM_&X0X)X?X?X,Y/Y !YLVLY <V <YLVLY DS 6Y 6R,R JX>W FV /X 'TCfFT2i CUGfB"
4091  "T 9U?U &V 7U 5] >iGU KU 6V;V >U2V NU2V$]5V NWJW 9WJW 9WJW 9WJW 9WJW 9WJW 8XFX"
4092  " KY /X -X -X -X -X -X -X -X ,X/Y)XMX;X%Y/Y)Y/Y)Y/Y)Y/Y)Y/Y#T-T'Y3]*X/X'X/X'X/X'X/X%X>X Ir "
4093  "GW=\\ GY 9S 3W /XDVDX$X2X$X2X$X"
4094  "2X$X2X V ;X0X 0X 7T 8d <k#~`!g Bd DW4W ?[ ?X7W LY !X /X 2VFV &VCV#Z"
4095  "JSGV KV?VAV!W 0V 'V 'V /d $V FV 5X8X <X NX -X ?VJX DX .X BX HX8X Y7X #V 1V C"
4096  "X >X$X-WJW EX6X Y .X.Y)X -X -Y .X/X'X -X -XBZ EX -XLV:VLX0XMX;X&Y-Y+X7X NY-Y+X7X!X KX <X/"
4097  "X(X2X$X<VKV<X6YCY JY@Y +Z MW /V MW -Y;Y \"Z ;WDX 0Z 2XDW >Z <W !X :WDY IW ,W HX8X "
4098  "MY 3Z *X 3X &X 7] <W 3W :V MW ;X :W:W 4Y @[ )\\ (Y 6X 8QEV :[ "
4099  " JW6W @VIW =Y 6X -Y-Y(]JXJ]'X0X)X?X?X-Y-Y #YKVKY =V =YKVKY IZ 9X 6T.T JW>W FV "
4100  ".X (TDgFT3j CTFhDT 9U?U &V 8U 4\\ =iGU KU 6V;V >U3V MU3V#\\5V MWJW 9WJW"
4101  " 9WJW 9WJW 9WJW 9WJW 8XFX LY .X -X -X -X -X -X -X -X ,X.Y*XMX;X&Y-Y+Y-Y+Y-Y+Y-Y+Y-Y%V/V)Y3"
4102  "_+X/X'X/X'X/X'X/X%Y@Y Is HW?^ ?Z /Z /Z /Z /Z /Z /Z6Y NZ 0Z /Z /Z /Z 8Y 1Y 3Z /Z /Z"
4103  " /Z /Z 3ZCV 5WDX DXCVCW%X0W%X0W%X0W%X0W V :X1X 0X 7T 9f =k#~`\"h Cf "
4104  "EW4W @\\ ?X8X LX !Y /X 2VFV 'VBV#XHSET KV?VAV!W 0V (W 'W .` \"V GW 5X"
4105  "8X <X NX -X @VIX DX .X BX HX8X X5W &Y 1Y FX >W\"W.XJX FX6X X -X.Y)X -X -X -X/X'X -X"
4106  " -XCZ DX -XLV:VLX0XLX<X&X+X+X7X NX+X+X7X!X KX <X/X(X2X$X<VKV<X5YEY HYBY +Z LW /W NW .Y9Y"
4107  " 'b ?WG^ 7b 9^GW A` Gl 2_GW MWG_ DW ,W ,W8Y MW ,WG^>^4WG_ 9` @WG^ 9^GW MWG\\ ;f Gm <W6W#"
4108  "X2X#W;X;W5Y7Y#W1X\"u 6W :V MW >^BV\"W:W 3X ?^ 0e AWG_ KV.X ?X <W6W HTG[ K}!WCWCW Ca"
4109  " 7p&{ NW6W AWHW >Z 7X -X+X)\\HXH\\(X0X)X?X?X-X+X $YJVJY >V >YJVJY Ma =X 7V0V JW@W E"
4110  "V .Y *TEiET5k DTEiDT :VAV &V 9U 3_ ;W6W NiGU KU 6V;V >U3V MU3V#_8V NXJX"
4111  " ;XJX ;XJX ;XJX ;XJX ;XJX :XEX LX -X -X -X -X -X -X -X -X ,X.Y*XLX<X&X+X+X+X+X+X+X+X+X+X&X"
4112  "1X*X3`+X/X'X/X'X/X'X/X$YBY Ht IW@_ Cb 7b 7b 7b 7b 7b 7b>a'b 7` 5` 5` 5` AW ,W ,W ,W DY EW"
4113  "G_ 9` 5` 5` 5` 5` (Z <`GV W6W MW6W MW6W MW6W#W1X NWG^ HW1X NWBVBW&W.W&WJP:PJW&W4PJW&W."
4114  "W!V :X2X 0X 6S 8g >k#~`#j Fj GW4W @\\ >W8W LX X .X 2VFV 'VBV$XGSCR "
4115  "KV?VBV X 1V (W 'W ,\\ V GW 5X8X <X NX -X AWIX DX /X BY HX8X X5W ([ 1[ HX ?W "
4116  "W/WHW FX6X!Y -X-Y*X -X .Y -X/X'X -X -XDZ CX -XLW<WLX0XKW<X'Y+X+X7X Y+X+X7X!X KX <X/X'X4X#"
4117  "X<VKV<X4XFY FXBX *Y KW /W NW /Y7Y +g AWIb ;f =bIW De Il 3bIW MWIc FW ,W ,W9Y LW ,WIbBb"
4118  "6WIc >f CWIb =bIW MWI^ =j Im <W6W\"W2W\"W<Z<W4X7X!W2W!u 6W :V MW @bEW\"W:W 2X @c 8j CW"
4119  "Ic MX0W =W <W6W IW/W\"VI^ L}!WCWCW Ee =t&{ W4W BWHW =Y 7X .X*Y*ZFXFZ(X0X)X?X?X.Y+X #WIVIW "
4120  " =V =WIVIW f ?X 8X2X KW@W EV .Z +SE[GVDS6ZDV DSDVDXDS 9UAU %V :U 2` <W6W"
4121  " NiGU KU 6V;V >U4V LU4V\"`:V GX /WHW ;WHW ;WHW ;WHW ;WHW ;WHW :XEX MY -X -X -X -X -X "
4122  "-X -X -X ,X-Y+XKW<X'Y+X,Y+X,Y+X,Y+X,Y+X'Z3Z,Y4WNY,X/X'X/X'X/X'X/X#XBX Gu JWB\\ Ag <g <g <g "
4123  "<g <g <gBe+f <e :e :e :e CW ,W ,W ,W Mc FWIc >f ;f ;f ;f ;f +Z >eJU NW6W MW6W MW6W MW6W\"W"
4124  "2W MWIb IW2W NWAVAW(W,W(WJR<RJW(W4RJW(W,W\"V 9W2X 1X 6T 9i ?k#~`#k Hl HW4W @] ?X9"
4125  "W LW NX .X 2VFV 'VCW$WFSAP KV?VBV NW 1V (V &W *X MV GV 5X6X =X N"
4126  "X -X AVHX DX /X BX GX8X X5X ,^ 1^ LX ?W MW0WHW FX6X!X ,X-Y*X -X .X ,X/X'X -X -XEZ B"
4127  "X -XKV<VKX0XKX=X'Y+Y,X7X Y+Y,X7X!X KX <X/X'X4X\"W=WKV<W3YGY FYDY +Z KW .V NW 0Y5Y /l C"
4128  "WJe ?j AeJW Eh Kl 5eJW MWJe GW ,W ,W:Y KW ,WJdDd7WJe @h DWJe AeJW MWJ_ ?l Im <W6W\"W2W!W=Z="
4129  "W2X9X W2W!u 6W :V MW BeFV!W;X 1W ?f =k CWJe NY2X =X =W6W JW-W$WI` N}!WCWCW Gi Av&{ "
4130  "W4W BVGW <Y 8X .X)X+ZEXEZ)X0X)X?X?X.Y+Y #UHVHU <V <UHVHU !j AX 9Z4Z KWBW DV -Z -"
4131  "TFY@RDT8XAV ETDVBWET :VCV %V ;V )X =W6W NiGU KU 6V;V >U5V KU5V GX<V FX /WHW"
4132  " ;WHW ;WHW ;WHW ;WHW ;WHW :WDX MX ,X -X -X -X -X -X -X -X ,X-Y+XKX=X'Y+Y-Y+Y-Y+Y-Y+Y-Y+Y'Z"
4133  "5Z+Y5WMY,X/X'X/X'X/X'X/X#YDY GX@^ KWCZ Al Al Al Al Al Al AlFh.j ?h =h =h =h EW ,W ,W ,W !g"
4134  " GWJe @h =h =h =h =h ,Z @hLV NW6W MW6W MW6W MW6W\"W2W MWJe KW2W W@VAW)W+W)WJT>TKW)W4TKW"
4135  ")W+W\"V 9X3X 2X 5T :k ?i\"~`$m Jn IW4W A^ ?X:X MW NY .X 2VFV 7~X2XFS"
4136  " <V?VCV MX 2V )W %W +X MV GV 5X6X =X NX -X BVGX DX /X BX GX8X X5X LX -X 7a 1a "
4137  "X @W KW2XHX GX6X!X ,X,X*X -X .X ,X/X'X -X -XFZ AX -XKV<VKX0XJW=X'X)X,X7X X)X,X7X!X KX <X/"
4138  "X'X4X\"X>VIV>X2YIY DYFY +Z JW .V NW 1Y3Y 1n DWLh Bm ChLW Gk Ll 6hLW MWKg HW ,W ,W;Y JW "
4139  ",WKfGg8WKg Cl FWLh ChLW MWK` @m Im <W6W\"X4X!W=Z=W1X;X NW3X!u 6W :V MW CgGV!W;W 0X ?"
4140  "g Am CWKg [4X >Y =W6W JW-W&YJb }!WCWCW Hk Dx&{ W4W CWFW <Y 9X /Y)X,ZDXDZ*X0X)X?X?X.X)X P #"
4141  "SGVGS %P 7V 9P0P CSGVGS !l BX 8ZGWFZ JWCX DV ,Z .SEW<PCS8V?V .P>P JSCVAVDS :WEV "
4142  "$V <V &W >W6W NiGU KU 6V;V BP>P /U5V KU5V EW=V FX 0XHX =XHX =XHX =XHX =XHX =XHX <XDX"
4143  " MX ,X -X -X -X -X -X -X -X ,X,X+XJW=X'X)X-X)X-X)X-X)X-X)X&Z7Z*X5WKX,X/X'X/X'X/X'X/X\"YFY F"
4144  "X=[ KWDY @n Cn Cn Cn Cn Cn CnHj1m Bk @k @k @k FW ,W ,W ,W $j GWKg Cl Al Al Al Al .Z Bs MW6"
4145  "W MW6W MW6W MW6W\"W3X MWLh LW3X V?V@W*V)W*VJV@VKW*V4VKW*V)W#V 9X4X 2X 4S :l ?i\"~`"
4146  "%o Lp JW4W A^ >W:X MW NX -X 2VFV 7~X2WES <V?VDV LX 2V )W %W -\\ V "
4147  "HW 5X6X =X NX .X BWGX DX 0X BY FX:X NX5X LX -X :d 1d $Y @V IV2WFW GX6X\"Y ,X,Y+X -X /Y "
4148  ",X/X'X -X -XH[ @X -XKW>WKX0XJX>X(Y)X,X7X!Y)X,X7X!Y LX <X/X&X6X!X>VIV>X1YKY BXFX +Z IW .W "
4149  " W 2Y1Y 2o EWMj Dn DjMW Hn Nl 7jMW MWLi IW ,W ,W<Y IW ,WLhIi9WLi En GWMj EjMW MWLa An I"
4150  "m <W6W!W4W W=Z=W1Y=Y MW4W u 6W :V MW DiIV W;W /W =g Cm CWLi![4W =Y =W6W KW+W(ZKd!}!"
4151  "WCWCW Im Fy&{ W4W CWFW ;Y :X /X'X-YCXCY*X0X)X?X?X/Y)X!R #QFVFQ $R 9V :R1R DQFVFQ \"n BX "
4152  "7ZJ\\JZ HWDW CV +[ 1TFW.T:W?V /Q?Q KTCVAWET :XIX $V =V #U >W6W NiGU KU 6V;V BQ"
4153  "?Q 0U6V JU6V BU>V EX 0WFW =WFW =WFW =WFW =WFW =WFW <XDX NY ,X -X -X -X -X -X -X -X ,X,Y,XJ"
4154  "X>X(Y)X.Y)X.Y)X.Y)X.Y)X%Z9Z*Y6WJX,X/X'X/X'X/X'X/X!XFX EX;Z LWDX ?o Do Do Do Do Do DoKn4n C"
4155  "n Cn Cn Cn HW ,W ,W ,W %l HWLi En Cn Cn Cn Cn /Z Cs LW6W MW6W MW6W MW6W!W4W LWMj LW4W "
4156  "W?V?V+W(V+WKXBXKV+W5XKV+W(V$W 8W4X 2X 5T ;n ?g!~_%p LZDZ JW4W A^ >W:W MW "
4157  " MX -X 2VFV 7~X2WES <WAWDV KX 3V )W %W /` \"V HV 4X6X =X Y .X BVFX DX 0X BX E"
4158  "X:X NX5X LX -X <e /e 'Y @V GV4XFX HX7X!X +X+X+X -X /X +X/X'X -X -XI[ ?X -XJV>VJX0XIW>X(X"
4159  "'X-X7X!X'X-X7X!Y LX <X/X&X6X!X>VIV>X1YKY AXHX +Z HW -V W 3Y/Y 3p FWMk Fo EkMW Io Nl 8"
4160  "kMW MWMk JW ,W ,W=Y HW ,WMjJj:WMk Gp HWMk GkMW MWMb Bo Im <W6W!W4W W>\\>W0X=X LW5X u 6W :V "
4161  " MW EkJV W<X /W >j Fn CWMk\"\\6X =Z >W6W KW+W)[Ke\"}!WCWCW Jo Hz&{ W4W DWDW ;Y ;X /X'X."
4162  "YBXBY+X0X)X?X?X/X'X#T HV IT :V ;T3T :V CV +o BX 6ZM`MZ GXFX CV *\\ 3SFW,S:V>V 0R@R "
4163  " KSBV@VDS 9e #V ?W \"V ?W6W NiGU KU 6V;V BR@R 1U6V JU6V BV?V EX 1XFX ?XFX ?XFX ?XFX"
4164  " ?XFX ?XFW =XCX NX +X -X -X -X -X -X -X -X ,X+X,XIW>X(X'X/X'X/X'X/X'X/X'X%Z;Z)X5VHX-X/X'X/"
4165  "X'X/X'X/X XHX DX:Y LWEX >p Ep Ep Ep Ep Ep EpMp6o Do Do Do Do HW ,W ,W ,W 'o IWMk Gp Ep Ep "
4166  "Ep Ep 0Z Ds KW6W MW6W MW6W MW6W!W5X LWMk MW5X V>V?W,V'W,VKZDYKW,V5YKW,V'W%W 8X5W 2"
4167  "X 4T ;o @g ~^%q NY@Y KW4W B` ?X<X MV LX -X 2VFV 7~X2WES ;VAVDV JY 4V )"
4168  "V $W 1d $V HV 4X6X =X X .Y CWFX DXLY =XEX 'Y EY<X MX5X LX -X ?e )e +Y ?V:X6V4WDW "
4169  "HX7X!X +X+X+X -X /X +X/X'X -X -XJ[ >X -XJW@WJX0XIX?X(X'X-X7X!X'X-X8Y Y MX <X/X%W6X W?WIV>"
4170  "W/YMY @YJY +Y GW -V W 4X+X 4YE\\ FWNXG\\ H]EX F\\GXNW J\\F[ GW ,\\GXNW MWNXG[ JW ,W ,W?Z GW"
4171  " ,WNXH[KXH[:WNXG[ H]H] IWNXG\\ I\\GXNW MWNXFQ C\\CW CW ,W6W!X6X NW?\\?W.X?X JW6W 1X 6W :V MW "
4172  " 9X=X\"[IZKW W=Y /W @m H]DV CWNXG[\"\\6W =[ >W6W LW)W*ZJWKY\"}!WCWCW K\\H] J{&{ V3W DWDW :Y "
4173  "<X /X'X.XAXAX+X0X)X?X?X/X'X$V IV JV ;V <V5V ;V CV ,^MSKW BX 5x EWFW BV ,_ 5TFW,S:V?W"
4174  " 1SAS LTBV@VDS 9d \"V @W U ?W6W NiGU KU 5V=V ASAS 2U7V IU7V @U@V DX 1WDW ?WDW ?"
4175  "WDW ?WDW ?WDW ?XFX >XCX NX +X -X -X -X -X -X -X -X ,X+X,XIX?X(X'X/X'X/X'X/X'X/X'X$Z=Z(X6WH"
4176  "X-X/X'X/X'X/X'X/X YJY DX9Y MWEW =YE\\ EYE\\ EYE\\ EYE\\ EYE\\ EYE\\ EYE]N\\G[7]EX E\\F[ F\\F[ F\\F[ "
4177  "F\\F[ IW ,W ,W ,W (p IWNXG[ H]H] G]H] G]H] G]H] G]H] 1Z E]H^ JW6W MW6W MW6W MW6W W6W KWNXG\\"
4178  " MW6W NV>V>V,V&V,VJZFYIV,V6YIV,V&V%W 7W6X 3X LR:T ;q @e N~^&s!Y>Y LW4W B` >W<X N"
4179  "W $x FX 2VFV 7~X2WES ;VAVEW IY 5V *W #W 4XNTNX &V IW 5X5X =X X .X "
4180  "CWEX Di AXH_ +X CX<X MX5X LX -X Be #e /Z @V<^IUDV5WDW HX8Y!X +X+X+X -X /X +X/X'X -X -XK["
4181  " =X -XIV@VIX0XHW?X(X'X-X7X!X'X-X8X NZ NX <X/X%X8X NX@VGV@X.c >XJX +Z GW -W !W 5X)X 5U>"
4182  "Z G_CZ I[>T FZC_ KZAZ HW -ZB_ M^BZ KW ,W ,W@Z FW ,^CZMVCZ;^BZ IZBZ I_CZ IZC_ M^ 5Y<S CW ,W"
4183  "6W W6W MW?\\?W.YAY JW6W 2Y 6W :V MW ;\\A\\%YDYLV NW>Y .W AXJa IZ<Q C^BZ MX8X =\\ ?W6W LW)"
4184  "W+YIXJY LW=W JWCWCW LZBZ K]F] ;W >W2W EWDW 9Y =X /X'X/YAXAY,X0X)X?X?X/X'X%X JV KX <V =X7"
4185  "X <V CV -\\JSHT BX 4v DXHX BV -b 7SEV*S;V?W 2TBT LSAV@VCS 9b !V AV MU ?W6W MhGU"
4186  " KU 5V=V ATBT 3U8V HU8V ?UAV CX 1WDW ?WDW ?WDW ?WDW ?WDW ?WDW ?XBX NX +X -X -X -X -X -"
4187  "X -X -X ,X+X,XHW?X(X'X/X'X/X'X/X'X/X'X#Z?Z'X7WGX-X/X'X/X'X/X'X/X NXJX CX9Y MWFW <U>Z FU>Z "
4188  "FU>Z FU>Z FU>Z FU>Z FU>eBZ9[>T FZAZ HZAZ HZAZ HZAZ JW ,W ,W ,W )r J^BZ IZBZ GZBZ GZBZ GZBZ"
4189  " GZBZ 1Z EZB[ JW6W MW6W MW6W MW6W W6W K_CZ MW6W V=V>V-V%V-VHZHYHV-V6YHV-V%V%W 7X7X "
4190  " 4X NU:T <s Ae N~^'u\"X<X LW4W BWNW >W<W MW $w EX 2~X2WES ;WCWEV GY "
4191  "9W #W 5XMTMX 'V IV 4X4X >X !Y 0Y BVDX Dk CXJc -X BX>X LX5Y MX -X Ee Le 3Z ?U=bKUC"
4192  "U6XDX IX9Y X +X+X+X -X /X +X/X'X -X -XL[ <X -XIV@VIX0XHX@X(X'X-X8Y!X'X-X8X N[ X <X/X%X8X "
4193  "NX@VGV@X.c =XLX +Z FW ,V !W AR9Y H]?Y KZ:R GY?] LY=Y IW -Y?] M]@Y KW ,W ,WAY DW ,]@X"
4194  "NV@X;]@Y JY>Y J]?Y KY?] M] 4X8P CW ,W6W X8X MW?\\?W-XAX IW7X 3Y 5W :V MW =_C_(YBXLV NW"
4195  "?Z -W CXC\\ KY ,]@Y LW8X >] ?W6W LW)W,YHWHY MW=W JWCWCW MY>Y L[B[ ;W >W2W FWBW 9Y >X 0X%X0X"
4196  "@X@X,X0X)X?X?X/X'X&Y JV KY =V >Y7Y =V CV .[HSFR BX 3t BWHW AV .WN\\ 9SFV)S;V?W 3UCU "
4197  " LSAV@VCS 7_ V BV LU ?W6W MhGU KU 5W?W AUCU 4U8V HU8V ?UAV CX 2XDX AXDX AXDX AX"
4198  "DX AXDX AXDX @XBX NX +X -X -X -X -X -X -X -X ,X+X,XHX@X(X'X/X'X/X'X/X'X/X'X\"ZAZ&X8WFX-X/X'"
4199  "X/X'X/X'X/X MXLX BX8X MWFW <R9Y GR9Y GR9Y GR9Y GR9Y GR9Y GR9a>Y;Z:R GY=Y JY=Y JY=Y JY=Y KW"
4200  " ,W ,W ,W *]E[ J]@Y JY>Y IY>Y IY>Y IY>Y IY>Y 2Z FY>Y JW6W MW6W MW6W MW6W W7X K]?Y NW7X "
4201  " V=V=U-V$U-VGZJYFU-V7YFU-V$U%W 7X8X &~X/X:T =t @c L~\\'v\"W:W LW4W CXNX ?X>X MV "
4202  " $x EX 2~X2WES :VDWEV FZ :W #W 7XKTKX )V IV 4X4X >X !X 0Y BWDX Dm FXKf "
4203  "/Y AYBY KX5Y MX -X Gd ~X d 5Y ?V>dLUCU6WBW IX;Z Y +X+Y,X -X 0Y +X/X'X -X -XM[ ;X -XIWBWIX"
4204  "0XGW@X)Y'Y.X8X!Y'Y.X9Y M] #X <X/X$X:X MX@VGV@X-a <YNY ,Z EW ,V !W AP6X H\\=Y LY7P HY="
4205  "\\ LX;X IW .Y=\\ M[=X KW ,W ,WBY CW ,[=]=W;[=X KY<Y K\\=Y MY=\\ M\\ 4X *W ,W6W NW8X MW@VNV@W,XC"
4206  "X GW8W 3Y 4W :V MW >aEa)X@XNW NWA[ ,W DW?[ LX +[=X KW:X =] ?W6W MW'W-XGWGX MW=W JWCWC"
4207  "W MX<Y NZ>Z <W >W2W FWBW 9Z ?X 0X%X0X@X@X,X0X(X@X@X/Y'Y(Y IV JY >V ?Y5Y >V CV .YFSDP B"
4208  "X 2q @XJX AV /WK[ :SFV)S;V@X 4VDV LSAV@VCS 6\\ MV CV KU ?W6W MhGU KU 4V?V @V"
4209  "DV 5U9V GU9V >UBV BX 2WBW AWBW AWBW AWBW AWBW AXDX @XBX Y +X -X -X -X -X -X -X -X ,X+Y-XGW"
4210  "@X)Y'Y1Y'Y1Y'Y1Y'Y1Y'Y\"ZCZ&Y9WEY.X/X'X/X'X/X'X/X MYNY BX8Y NWFW <P6X GP6X GP6X GP6X GP6X G"
4211  "P6X GP6_<X;Y7P GX;X JX;X JX;X JX;X KW ,W ,W ,W *Z?Y K[=X KY<Y KY<Y KY<Y KY<Y KY<Y 3Z GY<Y "
4212  "KW6W MW6W MW6W MW6W NW8W J\\=Y NW8W NV=V=V.V$V.VFZLYEV.V8YEV.V$V&W 6W8X &~X2\\<T =v"
4213  " Ab K~\\(x$W8W MW4W CXNX ?X>X NW $w DX $VBV#XFS :WFXEV H] ;W #W 9XITIX"
4214  " +V JW 4X4X >X \"Y 3[ BWCX Dn GXLi 1X ?ZFZ JY7Z MX -X Je M~X Me 9Y >U?gMUCV7WBW IX>\\"
4215  " NX *X*X,X -X 0X *X/X'X -X -XNZ 9X -XHVBVHX0XGXAX)X%X.X9Y!X%X.X:Y La 'X <X/X$X:X LWAWGV@W+"
4216  "_ :XNX ,Z DW ,W \"W &W H[;X MY .X;[ MX9X JW .X;[ M[<X LW ,W ,WCY BW ,Z<\\<X<[<X LX:X K"
4217  "[;X MX;[ M[ 3W )W ,W6W NW8W KWAVNVAW*XEX FW9X 4Y 3W :V MW ?cGc+Y?WNV MWD] +W DV=Z LX "
4218  "+Z;X LW:X >_ @W6W MW'W.YGWFX NW=W JWCWCW NX:X NY<Y <W >W2W FWBW 8Z @X 0X%X0X@X@X,X0X(X@X@X"
4219  "/X%X)Y HV IY ?V @Y3Y ?V CV /YES 6X 1\\H[ JcJc LV 0WI\\ =TFV)S;WAX 5WEW MTAVAWCS 3"
4220  "W 4~W.W KV ?W6W LgGU KU 4WAW @WEW 6U9V GU9V ?VBV BX 2WBW AWBW AWBW AWBW AWBW AWBW A"
4221  "XAX X *X -X -X -X -X -X -X -X ,X*X-XGXAX)X%X1X%X1X%X1X%X1X%X!ZEZ%X9WCX.X/X'X/X'X/X'X/X LXN"
4222  "X AX7X NWFW !W ,W ,W ,W ,W ,W ,]:X=Y .X9X LX9X LX9X LX9X LW ,W ,W ,W +Z=X K[<X LX:X KX:X K"
4223  "X:X KX:X KX:X 3Z GX<Z KW6W MW6W MW6W MW6W NW9X J[;X NW9X NU<V=V.U#V.UDZNYDV.U8YDV.U#V&"
4224  "V 5X9W %~X3]<T >x A` J~\\(y%W8W MW4W CXMW >W>W MV $x DX $VCV\"XFS 9X"
4225  "IXEV H_ <W #W ;YHTHY -V JV 3X4X >X #Y ?g AVBX Do HXMk 3Y >l HX7Z MX -X Me J~X Je "
4226  "=Y >V?hNUBU8XBX Ju MX *X*X,w Lq IX *~R'X -X -c 8X -XHVBVHX0XFWAX)X%X.X9Y!X%X.X;Z Ke ,X <X/"
4227  "X$X:X LXBVEVBX+_ 9` +Y CW +V \"W %W IZ9X NX .X9Z MW7W JW /X9Z MZ;X LW ,W ,WDY AW ,Z;["
4228  ";W<Z;X MY:Y LZ9X X9Z MZ 2W )W ,W6W NX:X KWAVNVAW*YGY EW:W 4Z 3W :V MW ?XMYIe,X>WNV MW"
4229  "Ib +W EW;Y MW *Z;X KV:W =_ @W6W NW%W/XFWFX NW=W JWCWCW NW8X!Y:Y =W >| GW@W 8Y @X 0X%X1Y@X@"
4230  "Y-X0X(X@X@X/XImIX*Y GV HY @V AY1Y @V CV /XDS 6X 0YDY JdLd LV 1WF[ >SFV'S<WBY 6XFX "
4231  " MS@VAVAS @~W/W JU >W6W LgGU KU 3WCW ?XFX 7U:V FU:V >UBV AX 3XBX CXBX CXBX CXBX"
4232  " CXBX CXBX BXAw?X *w Lw Lw Lw LX -X -X -X ,X*X-XFWAX)X%X1X%X1X%X1X%X1X%X ZGZ$X:WBX.X/X'X/X"
4233  "'X/X'X/X K` @X7X NWFW W ,W ,W ,W ,W ,W ,[8W=X -W7W LW7W LW7W LW7W LW ,W ,W ,W ,Y:X LZ;X M"
4234  "Y:Y MY:Y MY:Y MY:Y MY:Y \"Y=\\ LW6W MW6W MW6W MW6W MW:W IZ9X NW:W NV<V=V/V#V/VCcCV/V9YC"
4235  "V/V=X>V&V 4W:X %~X2TNV<S =y KWM^LW$~Z({&W7V MW4W CWLX ?X?W MV KX ,X"
4236  " %VBV!XGS 9gFV Ha >W \"W ;WFTFW -V JV 3X4X >X #Y ?f AWBX Dp IXNm 4X <j GX7Z MX -X"
4237  " !e G~X Ge AY =U?ZH^BU8W@W Jt LX *X*X,w Lq IX *~R'X -X -b 7X -XHWDWHX0XFXBX)X%X.X:Y X%X.X<"
4238  "Z Ih 0X <X/X#X<X KXBVEVBX*] 8` ,Z CW +V \"W %W IZ9X X -X9Z NX7X KW /X9Z MY9W LW ,W ,W"
4239  "EY @W ,Y:Z:W<Y9W MX8X LZ9X X9Z MY 1W )W ,W6W MW:W JWAVNVAW)XGX DW:W 4Y 3X :V MW @VHXK"
4240  "WGV,W<^ MWIa *W FW9Y NW *Y9W KW<X >` @W6W NW%W/WEWEW NW=W JWCWCW X8X!X8X =W >| GW@W 7Y AX "
4241  "0X%X1X?X?X-X0X(X@X@X/XImIX+Y FV GY AV BY/Y AV DX 1XCS 6X 0W@X KdLd LV 1VCZ ?SFV'S;WE"
4242  "[ 7XFX G~X .S@VBWAS @~W0W .P>W >W6W KfGU KU 3XEX >XFX 8U;V:W3U;VCZ9P>WCV:W/Y 3W@"
4243  "W CW@W CW@W CW@W CW@W CXBX CX@w?X *w Lw Lw Lw LX -X -X -X 5p9X-XFXBX)X%X1X%X1X%X1X%X1X%X N"
4244  "ZIZ#X:VAX.X/X'X/X'X/X'X/X K` @X7X NWFW W ,W ,W ,W ,W ,W ,[8X?X -X7X NX7X NX7X NX7X MW ,W "
4245  ",W ,W ,X9X LY9W MX8X MX8X MX8X MX8X MX8X \"X=] LW6W MW6W MW6W MW6W MW:W IZ9X NW:W NVLu"
4246  "KU/VLuKU/VBaAU/V:YAU/V=X=U&V 4X;X %~X2RLW>T >{!z'~Z)}(W6W NW4W DXLX ?X@X MV "
4247  " KX ,X %VBV!YHS 8eEV Ic ?W !W ;UETEU ,V KW 3X4X >X $Y >c ?WAX DWD^ JbG] "
4248  "5X 9d DY9[ MX -X #d D~X Dd DY <U@YD\\BU9X@X Kq IX *X*X,w Lq IX *~R'X -X -a 6X -XGVDVGX0XEWB"
4249  "X)X%X.X;Z X%X.X?\\ Gk 4X <X/X#X<X KXBVEVBX)[ 6^ ,Z BW +W #W %W IY7W X -W7Y NW5W KW 0X"
4250  "7Y MY9W LW ,W ,WFY ?W ,Y:Z:W<Y9W MW6W LY7W W7Y MY 1W )W ,W6W MW:W JWBVLVBW(XIX CW;X 5Y 2X "
4251  ":V MX BUDVKVDU.X<] LWI_ :WEW FV7X NW *Y9W JV<X >a AW6W NW%W0XEWEX W=W JWCWCW W6W!X8X "
4252  "=W >| HX@X 7Y BX 0X%X1X?X?X-X0X(X@X@X/XImIX,Y EV FY BV CY-Y BV DX 1XCS 6X 1W>W KeNe LV"
4253  " 1VB[ ASFV'S;YI] 9YGY F~X .S@VDX@S @~W1V ,TEZ >W6W JeGU IX +U 2YIY <YGY :U;V:W3U"
4254  ";VGa<TEZCV:W/X 3X@X EX@X EX@X EX@X EX@X EX@X DX@w?X *w Lw Lw Lw LX -X -X -X 5p9X-XEWBX)X%X"
4255  "1X%X1X%X1X%X1X%X MZKZ\"X;WAX.X/X'X/X'X/X'X/X J^ ?X7X NWFX !W ,W ,W ,W ,W ,W ,Z6W?X -W5W NW5"
4256  "W NW5W NW5W MW ,W ,W ,W -X7W LY9W MW6W MW6W MW6W MW6W MW6W \"W=^ LW6W MW6W MW6W MW6W MW;X "
4257  "IY7W NW;X NVLuKU/VLuKU/VA_@U/V;Y@U/V=X=U&V 4X<X $~X,W>T ?|\"}(~X)~(W6W NW4W DXKW >"
4258  "W@X MV KX ,X %VBV!ZIS 7cEV IYNZ8W 0W !W :RCTCR +V KW 3X4X >X %Y"
4259  " =b >V@X DS=\\ K`C[ 6Y 8b BX9[ Nd A~X Ad HY <VAX@ZBV:X?W Kq IX *X*X,w Lq IX *~R'X -X -a"
4260  " 6X -XGVDVGX0XEXCX)X%X.X=[ NX%X.u Fl 6X <X/X\"W<W IWCWEVBW([ 5\\ ,Z AW +W #W $V IY7X\"X"
4261  " -X7Y NW5W KW 0X7Y MX8X MW ,W ,WHZ >W ,X8X8W=X8X X6X MY7X\"X7Y MX 0W )W ,W6W MX<X IWCVLVCW&"
4262  "XKX AW<W 5Y 1W 9V LW 4P /TBVMVBT.X;\\ LWI` =\\HW GW7X NW *X8X KV=X >XMW AW6W NW%W0XEWDW W"
4263  "=W JWCWCW!X6X#X6X >W >| HW>W 6Y CX 0X%X1X?X?X-X0X'XAXAX.XImIX-Y DV EY CV DY+Y CV DX 2X"
4264  "BS 6X 1V<V KeNe LV 2V?Y ASFV'S:dNV :XFY E~X .S@i?S @~W2i >h =W6W JeGU IX 4g :g :"
4265  "YFX DgEV:X<gEVHe>hCV:X/X 3X?W EX?W EX?W EX?W EX?W EX@X EX?w?X *w Lw Lw Lw LX -X -X -X 5p9X"
4266  "-XEXCX)X%X1X%X1X%X1X%X1X%X LZMZ!X<W@X.X/X'X/X'X/X'X/X I\\ >X7X NWFY !V +V +V +V +V +V +Y6W@"
4267  "X ,W5W NW5W NW5W NW5W MW ,W ,W ,W -X7X MX8X X6X X6X X6X X6X X6X $X=_ MW6W MW6W MW6W MW6W "
4268  "LW<W HY7X NW<W MVLuKU/VLuKU/V@]?U/V<Y?U/V=X=U&V 3W<X $~X+V>S >}%~R)~V(~P)W6W NW4W"
4269  " DWJX ?XAW L~^ $X ,X %VCV N\\LS 6aDVAW0XLZ9W 0W !W :PATAP +V KV 2X"
4270  "4X >X &Z =e BW@X DP8[ L^?Z 7X :h EY;\\ \"d >~X ?e LY ;U@W>YAU:W>W Ks KX *X*X,w Lq IX6f+~R"
4271  "'X -X -b 7X -XGWFWGX0XDWCX)X%X.X@^ NX%X.s Bl 8X <X/X\"X>X IXDVCVDX)[ 4\\ -Z @W *V #W $"
4272  "W JX5W\"X -W5X W4W KW 0W5X MX7W MW ,W ,WIZ =W ,X8X8W=X7W W4W MX5W\"W5X MX 0X *W ,W6W LW<W HW"
4273  "CVLVCW&YMY AW=X 6Y 1X 9V LX 1X.Q /TA]AU/W:\\ LWIb A`JW GV5X NW +X7W KW>X >XMX BW6W W#W1WD"
4274  "WDW W=W JWCWCW!W4W#X6X >W >| HW>W 7Y BX 0X%X1X?X?X-X0X'XAXAX.XImIX.Y CV DY DV EY)Y DV "
4275  "DX 2XBS 6X 2W<W =^ =V 2V>Y BSFV'S9bMV ;XFY D~X .S@h>S @~W2i >g <W6W HcGU IX 4g 9"
4276  "e 8YFX EgEV;Y<gEVHf?gBV;Y0Y 3W>W EW>W EW>W EW>W EW>W EW>W EX?w?X *w Lw Lw Lw LX -X -X -X 5"
4277  "p9X-XDWCX)X%X1X%X1X%X1X%X1X%X Ke X=W?X.X/X'X/X'X/X'X/X I\\ >X7X NWEY \"W ,W ,W ,W ,W ,W ,X5W"
4278  "@X -W4W W4W W4W W4W MW ,W ,W ,W -W6X MX7W W4W W4W W4W W4W W4W $W=VMW MW6W MW6W MW6W MW6W "
4279  "LW=X HX5W NW=X MVLuKU/VLuKU/V?[>U/V=Y>U/V=X=U&V 3X=W 7X FW@T ?~&~T*~V)~R*W5V NW4"
4280  "W EXJX ?XBX L~^ $X ,X &VBV Mb 4]CVC]4XJZ:W 0W !W +T KV KV 2X4X >"
4281  "X 'Z <g EW?X +Z L]=Z 9Y <l GZ=] %e e!Y :UAW<XAU;X>X Lu MX *X*X,w Lq IX6f+~R'X -X -c "
4282  "8X -XFVFVFX0XDXDX)X%X.u MX%X.r ?l :X <X/X\"X>X IXDVCVDX)\\ 4Z ,Y ?W *V #W $W JX5W\"W ,W"
4283  "5X W3W LW 0W5X MX7W MW ,W ,WJY ;W ,X8X8W=X7W W4W MX5W\"W5X MX 0X *W ,W6W LW<W HWCVKUCW%XMX "
4284  "?W>W 6Y 0X 9V LX 5`3R 0T?[?T/W:[ KWId DbKW HW5X NW +X7W JV>W =WLX BW6W W#W1WDWDW W=W JWC"
4285  "WCW!W4W#W4W >W >| IX>X 9Y AX 0X%X1X?X?X-X0X'XAXAX.XImIX/Y BV CY EV FY'Y EV DX 2WAS ?r "
4286  "CV:V =^ =V 2V=Y CSFV'S8`LV <XFX B~X .S@e;S @~W2i >e :W6W GbGU IX 4g 8c 5XFX FgFV"
4287  ":Y<gFVGg@eAV:Y1Y 3X>X GX>X GX>X GX>X GX>X GX>X FX?w?X *w Lw Lw Lw LX -X -X -X 5p9X-XDXDX)X"
4288  "%X1X%X1X%X1X%X1X%X Jc NX>W>X.X/X'X/X'X/X'X/X HZ =X7X NWEZ #W ,W ,W ,W ,W ,W ,X4WAW ,W3W!W3"
4289  "W!W3W!W3W NW ,W ,W ,W .X5W MX7W W4W W4W W4W W4W W4W $W>VLW MW6W MW6W MW6W MW6W KW>W GX5W "
4290  "MW>W LVLuKU/VLuKU/V>Z>U/V>Y=U/V=X=U&V 2W>X 8Y FW@T ?~P(~V*~T(~Q)V4V NW4W EXJX >W"
4291  "BX L~^ $X ,X &VBV Ld 4WAVD`6XHZ;W 0W !W +T KV LW 2X4X >X 'Y ;i G"
4292  "V>X *Z M\\;Y 9X =p HZ?^ 'd Id$Y 9UAW<XAU;W<W Lw X *X*X,w Lq IX6f+~R'X -X -d 9X -XFVFV"
4293  "FX0XCWDX)X%X.t LX%X.p ;k ;X <X/X!X@X HXDVCVDX*^ 4X ,Z ?W *W $W $W JX5W\"W ,W5X W3W LW"
4294  " 0W5X MW6W MW ,W ,WKY :W ,W7W7W=W6W W4W MX5W\"W5X MX /Y ,W ,W6W LX>X GWEVJVEW#a >W>W 7Y 1Y "
4295  "8V KY 9e8T 0T?Z>T0X:[ KWIf GdLW HW4W MW ,W6W JV?X >XKW BW6W W#W2XDWDX!W=W JWCWCW!W4W#W4W"
4296  " >W >| IW<W :Y @X 0X%X1X?X?X-X0X&XBXBX-XImIX0Y AV BY FV GY%Y FV DX 2WAS ?r DW:W =\\ <V "
4297  "2V;W CSFV'S7]JV =XFX A~X .S@d:S (V Ii <a 8W6W FaGU IX 4g 6_ 2XFX GgGV:Z<gGVFUFY?"
4298  "a@V:Z2Y 2W<W GW<W GW<W GW<W GW<W GX>X GX>w?X *w Lw Lw Lw LX -X -X -X 5p9X-XCWDX)X%X1X%X1X%",
4299 
4300  // Second string:
4301  "X1X%X1X%X Ia MX?W=X.X/X'X/X'X/X'X/X GX <X7X NWDZ $W ,W ,W ,W ,W ,W ,X4WAW ,W3W!W3W!W3W!W3W"
4302  " NW ,W ,W ,W .W4W MW6W W4W W4W W4W W4W W4W $W?VKW MW6W MW6W MW6W MW6W KW>W GX5W MW>W "
4303  "LVLuKU/VLuKU/V?\\?U/V?Y<U/V=X=U&V 2W>X 8X DWBT ?~Q)~W)~R&~(V4V NW4W EWHW >WBW K~^ "
4304  " $X ,X &VBV Kg \"VEc8WFZ=W /W !W +T 4~W 5V 1X4X >X (Y -] IW>X )Y M[9X 9"
4305  "X >\\F\\ H[C` 'a Ca$Y 9UAV:WAU;W<W LX<\\!X *X*X,X -X 0X6f+X/X'X -X -XN[ :X -XEVHVEX0XCX"
4306  "EX)X%X.s KX%X.o 6h <X <X/X!X@X GWDVCVDW*_ 4X -Z >W )V $W 6i JX5X$X -X5X V2W LW 1W3W "
4307  "MW6W MW ,W ,WLY 9W ,W7W7W=W6W!X4X NX5X$X5X MW .[ .W ,W6W KW>W FWEVJVEW#a >W?X 8Z 4\\ 8V K["
4308  " =i<V 0S=Y=S0X:[ KW@^ IfMW HW4W MY .W6W JW@W =XKX CW6W W#W2WCWCW!W=W JWCWCW\"X4X%X4X ?W >W"
4309  "2W IW<W :Y @X 0X%X1X?X?X-X0X&XBXBX-X%X1~` GV H~` GV H~` GV DX 3XAS ?r DV8V =\\ <V 2V;X "
4310  "DSFV'S4W /XFX @~X .S@VIX;S (V Ii 8Z 5W6W D_GU IX 4g 3Y .XFX HgGV;TNU<gGVFQ@W;Z=V;T"
4311  "NU3Y 1W<W GW<W GW<W GW<W GW<W GW<W GX>X X *X -X -X -X -X -X -X -X ,X*X-XCXEX)X%X1X%X1X%X1X"
4312  "%X1X%X H_ LX@W<X.X/X'X/X'X/X'X/X GX <X7X NWD\\ 8i >i >i >i >i >i >i3WBX ,V2W!V2W!V2W!V2W NW"
4313  " ,W ,W ,W .W4W MW6W!X4X\"X4X\"X4X\"X4X\"X4X M~Y2X@VIW NW6W MW6W MW6W MW6W KW?X GX5X NW?X L"
4314  "VLuKU/VLuKU/V@^@U/V@Y;U/V=X=U&V 2X?W 8X CWBT ?~R*~X)~Q%}(V4W W4W FXHX ?XDX K~^ "
4315  " $X ,X 'WCV Ii &VEe:XEZ>W /W !W +T 4~W 5V 1X4X >X )Y )[ KW=X (Y N[9Y ;Y "
4316  "?Z@Z I]Gb '^ =^$X 9U@V:WAU<X<X MX9Z\"X *X*X,X -X 0X6f+X/X'X -X -XM[ ;X -XEVHVEX0XBWEX"
4317  ")X%X.r JX%X.q 4e =X <X/X!X@X GXFVAVFX*` 5X .Z =W )V $W :m JW3W$W ,W3W!W2W LW 1W3W MW"
4318  "6W MW ,W ,WMY 8W ,W7W7W=W6W!W2W NW3W$W3W MW -^ 2W ,W6W KX@X FWEVJVEW\"_ <W@W 7Y :b 7V Jb F"
4319  "mAX 0S<W<S0W8Y JW<[ KYHVMV GV3X MZ 0W6W IVAX >XIW CW6W!W!W3WCWCW!W=W JWCWCW\"W2W%W3X ?W >W"
4320  "2W JW;X <Y ?X 0X&Y1X?X?X-X0X&YCXCY-X%X2~a GV H~a HV I~b HV DX 3W@S ?r DV8V <Z ;V 2W;W "
4321  "DSFV'S <XFX =V .S@VGW<S (V \"W6W A\\GU IX 2XFX *V;TMU LV2V V;TMU4Z 2X<X IX<"
4322  "X IX<X IX<X IX<X IX<X IX=X X *X -X -X -X -X -X -X -X ,X*X-XBWEX)X%X1X%X1X%X1X%X1X%X G] KX@"
4323  "V;X.X/X'X/X'X/X'X/X GX <X8Y NWC\\ =m Bm Bm Bm Bm Bm Bm3WBW ,W2W\"W2W\"W2W\"W2W NW ,W ,W ,W /X4"
4324  "X NW6W!W2W\"W2W\"W2W\"W2W\"W2W M~Y2W@VHW NW6W MW6W MW6W MW6W JW@W FW3W MW@W KVLuKU/VLuKU/V"
4325  "A`AU/VAY:U/V=X=U&V 1W@X 9X BWBS >~R+~Z*~P#{'V4W W4W FXHX ?XDX K~^ $X "
4326  " ,X 'VBV Gi (VFg;WCZ?W /W !W +T 4~W 6W 1X4X >X *Y &Z LW=X (Y NZ7X ;X ?Z>Z ImNX "
4327  "'[ 8\\%Y 9UAW:WAU<W:W MX7Y#X *X*X,X -X 0X6f+X/X'X -X -XL[ <X -XEWJWEX0XBXFX)X%X.p HX%X.r"
4328  " 0a >X <X/X XBX FXFVAVFX+b 6X /Z <W )W %W =p JW3W$W ,W3W!| LW 1W3W MW6W MW ,W ,WNY 7"
4329  "W ,W7W7W=W6W!W2W NW3W$W3W MW -b 6W ,W6W JW@W EWFVHVFW!] ;WAX 8Y 9` 5V H` HrG[ 0S<W<S0W8Y"
4330  " JW:Y KXF^ HW2W Kc ;W6W IVAX >XIW CW6W!W!W3WCWCW!W=W JWCWCW\"W2W%W2W ?W >W2W JW:W =Y >X 0Y'"
4331  "X0X?X?X-X0X%XCXCX,X%X2~a GV H~a HV I~b HV DX 3W@S ?r DV8V <Z FW;W DSFV'S =XFX <V "
4332  ".S@VFW=S (V \"W6W <WGU IX 1XFX +V;SLU LV2V V;SLU5Z 1W:W IW:W IW:W IW:W IW:W I"
4333  "X<X IX=X X *X -X -X -X -X -X -X -X ,X*X-XBXFX)X%X1X%X1X%X1X%X1X%X F[ JXAW;X.X/X'X/X'X/X'X/"
4334  "X GX <X8X MWB] Bp Ep Ep Ep Ep Ep E~eBW ,|\"|\"|\"| NW ,W ,W ,W /W2W NW6W!W2W\"W2W\"W2W\"W2W\"W2W "
4335  "M~Y2WAWHW NW6W MW6W MW6W MW6W JWAX FW3W MWAX KV<V=V/V#V/VBbCV/VBY:V/V=X>V&V 1XAW 9"
4336  "X @WDT ?~S+~Z)}!y'W4W W4W FWFW >WDW J~^ *r ?V &VBV Eh *VEXIX<XBZ@W /W"
4337  " !W +T 4~W 5f 8V 0X4X >X +Y $Z NW<X 'X NZ7X ;X ?X:X HkMX '[ 7[%X 8UAV8VAU=X:X NX6"
4338  "X#X *X*X,X -X 0X6f+X/X'X -X -XK[ =X -XDVJVDX0XAWFX)X%X.m EX%X.XA\\ -^ ?X <X/X XBX FXFVAVFX,"
4339  "c 6X /Y ;W (V %W ?r JW3W$W ,W3W!| LW 1W3W MW6W MW ,W ,a 6W ,W7W7W=W6W!W2W NW3W$W3W M"
4340  "W ,e :W ,W6W JW@W DWGVHVGW N[ 9WBW 8Y 8^ 3V F^ I~X 0S;U;T1W8Y JW8X MXC\\ HW2W Ia ;W6W IWB"
4341  "W >XHX DW6W!W<W<W3WCWCW!W=W JWCWCW\"W2W%W2W ?W >W2W KX:X ?Y =X /X'X0Y@X@Y-X0X%YDXDY,X%X2~a "
4342  "GV H~a HV I~b HV DX 3W@S ?r DV8V ;X DW;V DSFV'S >XFX ;V .S@VFW=S (V \"W6W "
4343  ":UGU IX 0XFX -V;TLU MV0U!V;TLU6Y 0X:X KX:X KX:X KX:X KX:X KX:X JW<X X *X -X -X -X -X"
4344  " -X -X -X ,X*X-XAWFX)X%X1X%X1X%X1X%X1X%X F[ JXBW:X.X/X'X/X'X/X'X/X GX <X9Y MWA] Er Gr Gr G"
4345  "r Gr Gr G~gBW ,|\"|\"|\"| NW ,W ,W ,W /W2W NW6W!W2W\"W2W\"W2W\"W2W\"W2W M~Y2WBWGW NW6W MW6W MW6W "
4346  "MW6W IWBW EW3W LWBW IU<V=V.U#V.UCdDV.UCY9V.U=X>V&V 1XBX :X ?WDT ?~S,~[({ x&W4W W"
4347  "4W FWFX ?XFX JV \"q >V &VBV Af -VEXGX=W@ZBW .W !W +T 4~W 5f 8V 0X4X "
4348  ">X ,Y \"Y W;X 'X NZ7X <Y @Y:Y HiLX '^ =^%X 8UAV8VAU=X:X NX5X$X *X*X,X -X 0X(X+X/X'X -"
4349  "X -XJ[ >X -XDVJVDX0XAXGX)X%X.i AX%X.X>Z ,\\ ?X <X/X NWBW DWFVAVFW+XMY 7X 0Z ;W (V %W "
4350  "@s JW3W$W ,W3W!| LW 1W3W MW6W MW ,W ,` 5W ,W7W7W=W6W!W2W NW3W$W3W MW +g =W ,W6W JXBX DWGVH"
4351  "VGW N[ 9WBW 9Y 7^ 3V F^ I[Gr /S;U;T1W8X IW7X NWA[ HW2W F^ ;W6W HVCX >XGW DW6W!W<W<W3WCWC"
4352  "W!W=W JWCWCW\"W2W%W2W ?W >W2W KW9X ?Y =X /X'X/X@X@X,X0X$YEXEY+X%X2~a GV H~a HV I~b HV DX "
4353  "3W@S 6X 3V8V ;X DX<V DTFV)T >WEW :V .TAVEW?T (V \"W6W :UGU IX /WEW .V;"
4354  "TKU NV/U\"V;TKU7Y /X:X KX:X KX:X KX:X KX:X KX:X KX<X X *X -X -X -X -X -X -X -X ,X*X-XAXGX)X"
4355  "%X1X%X1X%X1X%X1X%X G] KXCW9X.X/X'X/X'X/X'X/X GX <X9Y MW?] Hs Hs Hs Hs Hs Hs H~hBW ,|\"|\"|\"|"
4356  " NW ,W ,W ,W /W2W NW6W!W2W\"W2W\"W2W\"W2W\"W2W M~Y2WBVFW NW6W MW6W MW6W MW6W IWBW EW3W LWBW "
4357  " IU<V=V.U#V.UDYMZEV.UDY8V.U#V&V 0WBX ;X >WDS >~T-~\\(y Mw&W4W W4W GXFX ?XFX JV "
4358  " #r >V 'WCV <c .VEWEW=W?ZCW .W !W :~W 5f 9W 0X4X >X -Y Y!W;X 'Y Y5X =X"
4359  " @Y8Y HgKX 'a Ca%X 8UAV8VAU=W8W NX4X%X *X+Y,X -X 0X(X+X/X'X -X -XI[ ?X -XDWLWDX0X@WG"
4360  "X)X&Y.X 0X&Y.X=Y *[ @X <X/X NXDX DXHW@VHX,YMZ 8X 1Z :W (W &W At JW3W$W ,W3W!| LW 1W3"
4361  "W MW6W MW ,W ,` 5W ,W7W7W=W6W!W2W NW3W$W3W MW )g ?W ,W6W IWBW CWGVHVGW MY 8WCX :Y 6` 5V H"
4362  "` IW@m -S;V<T1W8X IW7X W@[ HW2W Ia ;W6W HVCW >XFX EW6W!W<W<W3WCWCW!W=W JWCWCW\"W2W%W2W ?W "
4363  ">W2W KW8W @Y <X /X'X/X@X@X,X0X#YFXFY*X&Y2~a GV H~a HV I~b HV DX 3W@S 6X 3V8V ;X CX=V "
4364  " CSFV)S =WEW :V -SAVDW@S 'V \"W6W :UGU IX /WEW .V<TJU NV/U\"V<TJU8Z /W8W KW"
4365  "8W KW8W KW8W KW8W KX:X KX<X X *X -X -X -X -X -X -X -X ,X+Y-X@WGX)X&Y1X&Y1X&Y1X&Y1X&Y H_ LX"
4366  "DW9Y.X/X'X/X'X/X'X/X GX <X:Y LW>] Jt It It It It It I~iBW ,|\"|\"|\"| NW ,W ,W ,W /W2W NW6W!W"
4367  "2W\"W2W\"W2W\"W2W\"W2W M~Y2WCVEW NW6W MW6W MW6W MW6W IWCX EW3W LWCX IV=V=V.V$V.VFYKZFV.VFY"
4368  "7V.V$V&V 0XCW ;Y =WFT >~T-~\\'w Ku%W4W W4W GXEW >WFW IV #q =V 6~X "
4369  "JSN^ /VEWCW?W=ZDW .W !W :~W 5f 9V /X4X >X .Y MX\"W:X &X Y5X >Y @X6X FcJX &d Id"
4370  "%X 8UAV8VAU>X8X X4X$X +X+X+X -X /X)X+X/X'X -X -XH[ @X -XCVLVCX0X@XHX(X'X-X /X'X-X<Y *Z @X "
4371  "<X/X NXDX DXHV?VHX-YKY 8X 2Z 9W 'V &W B]?W JW3W$W ,W3W!| LW 1W3W MW6W MW ,W ,a 6W ,W"
4372  "7W7W=W6W!W2W NW3W$W3W MW 'g AW ,W6W IWBW CWHVFVHW NZ 7WDW :Z 6a 6V Jb IU;i ,S;V<S0W7W IW"
4373  "6W W?Z HW2W Kc ;W6W HWEX >XFX EW6W!W<W<W3WCWCW!W=W JWCWCW\"W2W%W2W ?W =V2V KX8X BY ;X /Y)Y/"
4374  "X@X@X,X0X#YFXGZ)X'X0~` GV H~` GV H~` GV DX 3W@S 6X 3V8V M| &Z?V CSFV)S:m AXFX ;V -S"
4375  "AVDW@S 'V \"W6W :UGU *m 5XFX /V;SIU V.T\"V;SIU9Z /X8X MX8X MX8X MX8X MX8X MX8X "
4376  "MX;X NX +X -X -X -X -X -X -X -X ,X+X,X@XHX(X'X/X'X/X'X/X'X/X'X Ha LXFW8X-X/X'X/X'X/X'X/X G"
4377  "X <X;Z LW<\\ L]?W J]?W J]?W J]?W J]?W J]?W J]?{BW ,|\"|\"|\"| NW ,W ,W ,W /W2W NW6W!W2W\"W2W\"W2"
4378  "W\"W2W\"W2W M~Y2WDVDW NW6W MW6W MW6W MW6W HWDW DW3W KWDW HV=V>V-V%V-VGYIZHV-VGY7V-V%V%V "
4379  "/WDX ;X <WFT >~T-~\\'v Is$W4W W4W GWDX ?XGW HV %r =V 6~X JSJ[ 0VEV"
4380  "AV?W<ZFW -W !W \"V Lf 9V /X5X =X /Z MX\"V9X &X NX5X >X ?X6X D`IX $d Ne#X 8UAV8"
4381  "VBU=x X4X$X +X+X+X -X /X)X+X/X'X -X -XG[ AX -XCVLVCX0X?WHX(X'X-X /X'X-X;Y *Y @X <X/X MXFX "
4382  "CXHV?VHX-XIY 9X 3Z 8W 'V &W CZ;W JW3W$W ,W3W!| LW 1W3W MW6W MW ,W ,b 7W ,W7W7W=W6W!W"
4383  "2W NW3W$W3W MW %f BW ,W6W IXDX BWIVFVIW N\\ 8WEX :Y .[ 7V K\\ BT8e *S<X=S0W7V HW6X\"W=X GW2"
4384  "W Me ;W6W GVEX >WDW EW6W!W<W<W3WCWCW!W=W JWCWCW\"W2W%W2W ?W =W4W KW6W CY :X .X)X.YAXAY,X0X\""
4385  "ZHXHZ(X'X/Y AV BY FV GY%Y FV DX 3W@S 6X 2V:V L| %ZAV BSEV*S:m @XFX <V -SAVCWAS "
4386  " 'V \"W6W :UGU *m 6XFX .V<TIU V/U\"V<TIU9Y .x Mx Mx Mx Mx Mx Mu NX +X -X -X -X -X "
4387  "-X -X -X ,X+X,X?WHX(X'X/X'X/X'X/X'X/X'X Ic MXGW7X-X/X'X/X'X/X'X/X GX <X=[ KW:[ NZ;W KZ;W K"
4388  "Z;W KZ;W KZ;W KZ;W KZ;{BW ,|\"|\"|\"| NW ,W ,W ,W /W2W NW6W!W2W\"W2W\"W2W\"W2W\"W2W &WEVCW NW6W "
4389  "MW6W MW6W MW6W HWEX DW3W KWEX GV>V>V,V&V,VIYGZIV,VIY6V,V&V&W /XEW N~X'VGT =~T-~\\"
4390  "&u Ir#W4W NV4W HXDX ?XHX HV KX ,V 6~X JSHZ 2VDVAV?W;ZGW -W !W \"V "
4391  "Lf :W .X6X =X 0Z LY#~ /X NX5X >X @X5Y AYFX !d >~X >d X 8UAV8VBU>z!X3X%X +X+X+X -X /X"
4392  ")X+X/X'X -X -XF[ BX -XCWNWCX0X?XIX(X'X-X /X'X-X:X )Y AX <X/X MXFX BWHV?VHW-YIY 9X 3Y 7W 'W"
4393  " 'W CX9W JW3W$W ,W3W!W 'W 1W3W MW6W MW ,W ,WNZ 8W ,W7W7W=W6W!W2W NW3W$W3W MW !c CW ,"
4394  "W6W HWDW AWIVFVIW N] 8WFW :Y *Y 8V KY ?R3` (S<X=S0W7V HW5W\"W=X GW2W N[ 0W6W GWFW >XDX FW"
4395  "6W!W<W<W3WCWCW!W=W JWCWCW\"W2W%W2W ?W =W4W LX6X DY :X .X)X-XAXAX+X0X!ZIXIZ'X'X.Y BV CY EV"
4396  " FY'Y EV DX 3W@S 6X 2V:V L| $[CV BTFW,T:m ?XFX =V -TBVBVBT 'V \"W6W :UGU "
4397  " *m 7XFX .V<THU!V/U\"V<THU:Y .z z z z z Nx Nv NX +X -X -X -X -X -X -X -X ,X+X,X?XIX(X'X/X'"
4398  "X/X'X/X'X/X'X Je NXGV6X-X/X'X/X'X/X'X/X GX <X@^ KW9[ X9W KX9W KX9W KX9W KX9W KX9W KX9W MW "
4399  ",W ,W ,W ,W )W ,W ,W ,W /W2W NW6W!W2W\"W2W\"W2W\"W2W\"W2W &WFVBW NW6W MW6W MW6W MW6W GWFW CW3"
4400  "W JWFW FV>V?W,V'W,VJYEZKW,VJY6W,V'W&W /XFX N~X'WHT =~T-~\\%s Gp\"W4W NV4V GXCW >WH"
4401  "X HW LX ,V 6~X JSGY 3VDWAW@W:ZIW ,W !W \"V Lf :W .X6X =X 1Z JX#"
4402  "~ /X NX5X ?Y @X4X .X Md A~X Ad LX 8UAV8VBU>z!X3X%X +X+X+X -X /X)X+X/X'X -X -XE[ CX -XB"
4403  "VNVBX0X>WIX(X'X-X /X'X-X9X *Y AX <X/X MXFX BXJW?WJX.YGY :X 4Z 7W 'W 'W DX8W JW3W$W ,"
4404  "W3W!W 'W 1W3W MW6W MW ,W ,WLY 9W ,W7W7W=W6W!W2W NW3W$W3W MW K_ DW ,W6W HXFX AWIVFVIW ^ 8W"
4405  "FW ;Y (Y 9V LY >Q.X $T>Z?T0W8W HW5W\"W<W GW2W Y -W6W GWGX >WCX FW6W!W<W<W3WCWCW!W=W JWCWC"
4406  "W\"W2W%W2W ?W =W4W LX6X EY 9X .Y+Y-YBXBY+X0X ZJXJZ&X'X-Y CV DY DV EY)Y DV DX 3W@S 6X 2W"
4407  "<W L| #\\FW ASFW,S9m >XFX >V ,SBVBWCS &V \"W6W :UGU *m 8XFX .V<TGU\"V.U#V<T"
4408  "GU;Y -z z z z z z v NX +X -X -X -X -X -X -X -X ,X+X,X>WIX(X'X/X'X/X'X/X'X/X'X KZMZ XHW6X-X"
4409  "/X'X/X'X/X'X/X GX <u JW7Y!X8W LX8W LX8W LX8W LX8W LX8W LX8W MW ,W ,W ,W ,W )W ,W ,W ,W /W2"
4410  "W NW6W!W2W\"W2W\"W2W\"W2W\"W2W &WGWBW NW6W MW6W MW6W MW6W GWFW CW3W JWFW FW?V?V+W(V+WKXCY"
4411  "KV+WKX5V+W(V%W .WFX N~X'WHT =~T-~\\$q Eo\"W4W NV4V GWBW >XIW GW LX "
4412  " ;~X JSFX 3VDV?V@W9ZJW +V \"W !V V -X6X =X 2Z IX#~ /X NX5X ?X ?X4X .X Jd D~"
4413  "X Dd IX 8UAV8VCV>z!X3X%Y ,X,Y+X -X /Y*X+X/X'X -X -XD[ DX -XBVNVBX0X>XJX(Y)X,X /Y)X,X9Y *X "
4414  "AX <X/X LXHX AXJV=VJX.XEY ;X 5Z 6W &V 'W DW7W JW3W$W ,W3W!W 'W 1W3W MW6W MW ,W ,WKY "
4415  ":W ,W7W7W=W6W!W2W NW3W$W3W MW H\\ DW ,W6W GWFW @WJVDVJW!` 9WGX <Y &X 9V LX =P (T?\\@T0W8"
4416  "X IW5W\"W<W GW2W X ,W6W FVGW >XBW FW6W!W<W<W3WCWCW!W=W JWCWCW\"W2W%W2W ?W =W4W LW4W FY 8X -X"
4417  "+X+YCXCY*X0X N\\MXM\\%Y)X+Y DV EY NQFVFQ Y+Y CV DX 3W@S 6X 1V<V K| ![HW @TFW.T9m =XFX"
4418  " ?V ,TCVAVDT &V \"W6W :UGU *m 9XFX -V<SFU\"V/U\"V<SFU;X ,z z z z z z v NY ,X -"
4419  "X -X -X -X -X -X -X ,X,Y,X>XJX(Y)X.Y)X.Y)X.Y)X.Y)X KZKZ!YJW6X,X/X'X/X'X/X'X/X GX <t IW6Y\"W"
4420  "7W LW7W LW7W LW7W LW7W LW7W LW7W MW ,W ,W ,W ,W )W ,W ,W ,W /W2W NW6W!W2W\"W2W\"W2W\"W2W\"W2W "
4421  " &WHWAW NW6W MW6W MW6W MW6W GWGX CW3W JWGX EV?V@W*V)W*VJVAWKW*VJV5W*V)W%W .XGW M~X"
4422  "&WJT <~S,kNn#o Cm!W4W NV4V HXBX ?XJX FW MY <~X JSEX 5VCV?V@W8ZLW "
4423  "*W #W !V V -X6X =X 3Z HX#~ /X NX5X @Y ?X4X /X Ge G~X Ge GX 8UAV9WCU>|\"X3X$X ,"
4424  "X,X*X -X .X*X+X/X'X -X -XC[ EX -XA\\AX0X=WJX'X)X,X .X)X,X8X *X AX <X/X LXHX AXJV=VJX/YEY ;X"
4425  " 6Z 5W &V 'W DW7W JW3W$W ,W3W!W 'W 1W3W MW6W MW ,W ,WJY ;W ,W7W7W=W6W!W2W NW3W$W3W M"
4426  "W EZ EW ,W6W GWFW ?WKVDVKW!b 9WHW <Y $W 9V LW BTAVNUAT/W8X IW5W#W;V FW2W!X +W6W FWIX"
4427  " >XBX GW6W!W<W<W3WCWCW!W=W JWCWCW\"W2W%W2W ?W =W4W MX4X HY 7X -Y-Y+ZDXDZ*X0X Mt#X)X*Y EV "
4428  "FY NSGVGS Y-Y MQFVFQ X 3W@S 6X 1W>W 9X =\\KW >SEW<PCS 6XFX @V +SCVAWES %V "
4429  "\"W6W :UGU &XFX -V<TFU#V/U\"V<TFU<X ,|\"|\"|\"|\"|\"|\"w MX ,X -X -X -X -X -X -X -X ,X,X+X="
4430  "WJX'X)X-X)X-X)X-X)X-X)X LZIZ!XKW5X,X/X'X/X'X/X'X/X GX <s HW5X\"W7W LW7W LW7W LW7W LW7W LW7W"
4431  " LW7W MW ,W ,W ,W ,W )W ,W ,W ,W /W2W NW6W!W2W\"W2W\"W2W\"W2W\"W2W &WIW@W NW6W MW6W MW6W MW6W"
4432  " FWHW BW3W IWHW DW@VAW)W+W)WJT?UKW)WJT5W)W+W$W -WHX M~X&WJT ;eMQMe+jNQNj!m Bl W4"
4433  "W NW6W HXBX >WJX FW LX <~X JSEX 6WCV?V@W7ZMW *W #W !V !W -X6"
4434  "X =X 4Z GX#~ /X NX5X @X >X4X /X De J~X Je DX 8U@V:WDV>|\"X3X$X ,X-Y*X -X .X*X+X/X'X -X"
4435  " -XB[ FX -XA\\AX0X=XKX'X*Y,X .X*Y,X8Y +X AX <Y1Y KWHW ?WJV=VJW/YCY <X 7Z 4W &W (W EW6"
4436  "W JX5X$X -X5X!X (W 0W5X MW6W MW ,W ,WIY <W ,W7W7W=W6W!X4X NX5X$X5X MW CX EW ,W6W GXHX ?WK"
4437  "VDVKW!XNY :WIX =Y #X :V MX BUCVMVBT/W9Y IW5W#W<W FW3X!W *W6W EVIX ?X@W GW6W!W=Y=W3XDW"
4438  "DX!W=W JWCWCW\"X4X%X4W >W <W6W LX4X HY 7X ,X-X)ZEXEZ)X0X Lr\"X)X)Y FV GY NUHVHU Y/Y MSGVGS"
4439  " !X 3XAS 6X 0W@W 8X ;\\NW =TEX@RDT 5XFY BV +TDV@WGT %V \"W6W :UGU (YF"
4440  "X ,V=TEU#V0U!V=TEU<X ,|\"|\"|\"|\"|\"|\"w MX ,X -X -X -X -X -X -X -X ,X-Y+X=XKX'X*Y-X*Y-X*Y-X*Y-"
4441  "X*Y MZGZ\"XLW5Y,Y1Y'Y1Y'Y1Y'Y1Y GX <r GW4X$W6W MW6W MW6W MW6W MW6W MW6W MW6X NX -X -X -X -X"
4442  " *W ,W ,W ,W /W2W NW6W!X4X\"X4X\"X4X\"X4X\"X4X &WIV@X NW6W MW6W MW6W MW6W FWIX BX5X IWIX "
4443  "CWAVAW(W,W(WJR=SJW(WJR4W(W,W$W -XIX M~X&WJS :dLQLd+iMQNj!l @j NW4W NW6W HW@W >WJW DW"
4444  " MX .VCV :SDW 6VBV?V@W6b )W #W !V !V +X8X <X 5Z FX#~ /X MW5"
4445  "X @X >X4X /X Ad L~X Ld AX 8VAV:WDU=|\"X3X$Y -X-Y*X -X .Y+X+X/X'X -X -XA[ GX -XA\\AX0X<WK"
4446  "X'Y+X+X .Y+Y,X7X +X AX ;X1X JXJX ?XLW=WLX/XAY =X 7Y 3W %V (W EW7X JX5W\"W ,W5X W (W 0"
4447  "W5X MW6W MW ,W ,WHY =W ,W7W7W=W6W W4W MX5W\"W5X MW BX FW ,W6W FWHW >WKVDVKW\"XLX 9WJW =Z #X"
4448  " :V MX AUEVKVDU/X:Y IW5W#W<W EW4W!X *W6W EVJX >X@W GW6W!W=Y=W2WDWDW W=W JWCWCW\"X4W#W4"
4449  "W >W <W6W LW2W IY 6X ,Y/Y(ZFXFZ(X0X Kp!Y+X'Y GV HY NWIVIW Y1Y MUHVHU \"X 2WAS 6X 0YDY 8X"
4450  " :c <TE[FUDS 3XFY CV *SDV@WGS $V \"W6W :UGU )YFX ,V=TDU$V0V\"V=TDU=X +"
4451  "|\"|\"|\"|\"|\"|#x MY -X -X -X -X -X -X -X -X ,X-Y+X<WKX'Y+X,Y+X,Y+X,Y+X,Y+X MZEZ#YNW4X*X1X%X1X"
4452  "%X1X%X1X FX <p EW4X$W7X MW7X MW7X MW7X MW7X MW7X MW7Y MW ,W ,W ,W ,W *W ,W ,W ,W .W4W MW6W"
4453  " W4W W4W W4W W4W W4W $WKV?W MW6W MW6W MW6W MW6W EWJW AX5W GWJW BXBVBW'X.W'XJP;QJW'XJP"
4454  "4W'X.W#V ,XIW L~X%WLT :dLQLc*iMQMi k ?i NW4W NW6W IX@X ?XLX DW MY "
4455  " 0VBV :SDW 7VAV?V@X6a )W #W !V !V +X8X <X 6Z EX#~ 0Y MW5X AY >X4X 0X =d ~X"
4456  " d LUAW<XEV>X2X#X3X#X -X.Y)X -X -X+X+X/X'X -X -X@[ HX -X@Z@X0X<XLX&X+X+X -X+X+X7Y ,X AX "
4457  ";X1X JXJX ?XLV;VLX0YAY =X 8Z 3W %V (W EW7X JX5W\"W ,W5X W (W 0W5X MW6W MW ,W ,WGY >W "
4458  ",W7W7W=W6W W4W MX5W\"W5X MW BX FW ,W7X FWHW >WLVBVLW#YKX :WJW =Y !W :V MW @VHXJWHV-W:"
4459  "Y IW5W#W<W EW4W!W )W6W EWKX ?X?X HW6W!X>Y>W1WDWDW W=W JWCWCW\"X4W#W4W >W <W6W MX2X KY 5X +Y"
4460  "1Y'[GXH\\(X0X Jn NX+X&Y HV IY NYJVJY Y3Y MWIVIW #X 2WAS 6X 0[H[ 8X :V %` :TEiET 2YGY "
4461  " DV *TEV?WIT $V \"W6W :UGU *YGY ,V<SCU%V0V\"V<SCU=X ,X2X$X2X$X2X$X2X$X2X$X2X"
4462  "$X8X LX -X -X -X -X -X -X -X -X ,X.Y*X<XLX&X+X+X+X+X+X+X+X+X+X NZCZ#`3X*X1X%X1X%X1X%X1X FX"
4463  " <m BW3W$W7X MW7X MW7X MW7X MW7X MW7X MW7Y MW ,W ,W ,W ,W *W ,W ,W ,W .W4W MW6W W4W W4W W4"
4464  "W W4W W4W 5Z IWLV>W MW7X MW7X MW7X MW7X EWJW AX5W GWJW AXCVCW%X0W%X0W%X0W%X0W\"V +WJX "
4465  " ?X 2WLT 9bKQKb)gLQMh Mi =g MW4W MV6W IX@X ?XLX CW MX 0VBV :SDW "
4466  "7VAV?V@X5_ (W #W !V \"W +X8X <X 7Z DX 5X 'X LX7X @X =X4X 0X ;e Le JUAW<XFV"
4467  "=X1W#X3X#Y .X.Y)X -X -Y,X+X/X'X -X -X?[ IX -X@Z@X0X;XMX&Y-Y+X -Y-Y+X6X ,X AX ;X1X IXLX >XL"
4468  "V;VLX1Y?Y >X 9Z 2W %W )W EW7X JX5W\"X -W5X X )W 0X7Y MW6W MW ,W ,WFY ?W ,W7W7W=W6W W4"
4469  "W MX5W\"W5X MW AW FW ,W7X FXJX =WMVBVMW#YJY ;WKX >Y W :V MW ?dId,W;Z IW5W#W=W DW4W!W"
4470  " )W6W DVKW >X>W HW6W W>Y>W1WDWDW W=W JWCWDX\"X4W#W4W >W ;V7W LX2X LY 4X *X1X%]JXJ]'X0X Hj L"
4471  "Y-Y%Y IV JY LYKVKY MY5Y MYJVJY $X 2XBS 6X 2q 9X :V #\\ 7TDgFT /XFX EV )TFV>VJT #"
4472  "V \"W6W :UGU +XFX *V=TCU%V1V!V=TCU=X ,X1W$X1W$X1W$X1W$X1W$X2X%X7X LY .X -X -X -"
4473  "X -X -X -X -X ,X.Y*X;XMX&Y-Y+Y-Y+Y-Y+Y-Y+Y-Y ZAZ$_3Y*X1X%X1X%X1X%X1X FX <i >W3W$W7X MW7X M"
4474  "W7X MW7X MW7X MW7X MW7Z NX -X -X -X -X +W ,W ,W ,W .W4W MW6W W4W W4W W4W W4W W4W 5Z IWMV=W"
4475  " MW7X MW7X MW7X MW7X EWKX AX5W GWKX @XDVDX$X2X$X2X$X2X$X2X\"V +XKW ?X 1WMT 7`JQKa"
4476  "'fLQLf Kg <f LW4W MW8W HW>W >WLW BX NY 1VBV :SDW 8V@V?V?W4] &V $W "
4477  " V \"V *Y:Y <X 8Z DY 5X 'X KW7X @X =X5Y 1Y 8e #e GU@W>YGW>X0X$X4Y\"Y /X/Y(X -X"
4478  " ,Y-X+X/X'X -X -X>[ JX -X@Z@X0X;XMX%Y/Y*X ,Y/Y*X6Y -X AX ;Y3Y IXLX =WLV;VLW0X=Y ?X :Z 1W $"
4479  "V )W EW8Y JY7X\"X -X7Y X )W 0X7Y MW6W MW ,W ,WEY @W ,W7W7W=W6W X6X MY7X\"X7Y MW AW FW"
4480  " ,X8X EWJW <WMVBVMW#XHX :WLW >Y NW :V MW >bGc,W;[ JW6X#W=W DX6X!W )W6W DVLX >W=X IW7"
4481  "X W>Y>W1XEWEX W=W IWDWDW!Y6X#X6X >W ;W8W MX0X MY 4X *Y3Y$^LXL^&X0X Ff IY/Y#Y JV KY JYLVL"
4482  "Y KY7Y KYKVKY #X 2XBS 6X 3t ;X :V ![ 8TCfFT .XFX FV )UGV>WKT MW7X :UGU "
4483  " ,XFX *V=TBU&V2W!V=TBU=X -X0X&X0X&X0X&X0X&X0X&X0W%X7X KY /X -X -X -X -X -X -X -X ,X/Y)"
4484  "X;XMX%Y/Y)Y/Y)Y/Y)Y/Y)Y/Y Z?Z$^4Y)Y3Y%Y3Y%Y3Y%Y3Y FX <X -W3W$W8Y MW8Y MW8Y MW8Y MW8Y MW8Y "
4485  "MW8[ NX -X -X -X -X +W ,W ,W ,W .X6X MW6W X6X X6X X6X X6X X6X 5Z I_=X MX8X MX8X MX8X MX8X "
4486  "DWLW @Y7X FWLW >XEVFY\"X5Y\"X5Y\"X5Y\"X5Y!V *WLX @X /WNT 7`JQJ_&eKQKe Je :d KW4W MW8"
4487  "W HW>X ?XNX AX Y 1VCV 9SDW 9V?V?V?X4\\ &W %W V \"V )X:X ;X 9Z"
4488  " CX 4X (Y KW7X AX <Y6Y 1X 4e )e DVAX@ZHW=X0X$X4Y\"Y*P&X0Z(X -X ,Y-X+X/X'X -X -X=[ K"
4489  "X -X?X?X0X:XNX%Y/Y*X ,Y/Y*X5X .Y AX :X3X HXLX =XNW;WNX1Y=Y ?X ;Z 0W $V )W EW8Y JY7W "
4490  "W ,W7Y NX *W /W8Z MW6W MW ,W ,WDY AW ,W7W7W=W6W NW6W LY7W W7Y MW AW FW ,X9Y EWJW <WMVBVMW"
4491  "$XFX ;WMX ?Y MW :V MW =`Ea+X<[ JW6W\"W>W BW6W W )W6W DWMX ?X=X IX8X W?[?W0WEWEW NW=W "
4492  "IWDWDW!Y6W!W6W =W ;W8W MX0X NY 3X )Y5Y\"z%X0X C` FY/Y\"X JV KX HYMVMY IX7X IYLVLY \"X 1XCS"
4493  " 6X 4v <X :V [ 8TBbET ,WEW FV (T$T LX8X :UGU ,WEW )V=m,V3W V=mCX -"
4494  "X0X&X0X&X0X&X0X&X0X&X0X&X7X KY*P&X -X -X -X -X -X -X -X ,X0Z)X:XNX%Y/Y)Y/Y)Y/Y)Y/Y)Y/Y!Z=Z"
4495  "%]3Y(X3X#X3X#X3X#X3X EX <X -W3W$W8Y MW8Y MW8Y MW8Y MW8Y MW8Y MW8[ MW ,X -X -X -X ,W ,W ,W "
4496  ",W -W6W LW6W NW6W MW6W MW6W MW6W MW6W 4Z H^=W LX9Y MX9Y MX9Y MX9Y DWMX @Y7W EWMX =Y8Y "
4497  "Y8Y Y8Y Y8Y Y8Y V *WLX AX .WNT 6^IQI]$cKRJc Id 8c KW4W MX:X IX>X ?XNX AY "
4498  " Y4P VBV 9SDW 9V?V?V?Y4Z %W %W V #W )X:X ;X :Z CY 4X (Y KX9Y AX ;X6X 1"
4499  "Y 1e /e @U@XB[JX<X/W$X4X Y,Q&X1Z'X -X +Y.X+X/X'X -X -X<[ LX -X?X?X0X:XNX$Y1Y)X +Y1Y"
4500  ")X5Y /X @X :X4Y GXNX <XNV9VNX2Y;Y @X ;Y /W $W *W EW9Z JZ9X X -X9Z NX *W /X9Z MW6W MW"
4501  " ,W ,WCY BW ,W7W7W=W6W NX8X LZ9X X9Z MW AW FW +W9Y EXLX <WNV@VNW%YEX ;WNW ?Y LW :V MW "
4502  " <^C_)W=\\ JX7W\"W>W BX8X W )W6W CVNX >W;W IX8X X@[@X0XFWEW NW=W IWDWEX!Z8X!X8X =W :W:W LX"
4503  "0X Y 2X (Y7Y Nv#X0X ?X AY1Y V IV JV FYNVNY GV5V GYMVMY !X 1XCS 6X 5x =X :V MZ 8T?ZBT"
4504  " *VDV FV 'T&T KX8X :UGU ,VDV )V<m-V3V NV<mCX -X/W&X/W&X/W&X/W&X/W&X0X"
4505  "'X6X JY,Q&X -X -X -X -X -X -X -X ,X1Z(X:XNX$Y1Y'Y1Y'Y1Y'Y1Y'Y1Y!Z;Z%[3Y'X4Y#X4Y#X4Y#X4Y EX"
4506  " <X -W3W$W9Z MW9Z MW9Z MW9Z MW9Z MW9Z MW9] NX -X -X -X -X ,W ,W ,W ,W -X8X LW6W NX8X MX8X "
4507  "MX8X MX8X MX8X 4Z H]=X KW9Y LW9Y LW9Y LW9Y CWNW ?Z9X DWNW ;Y;Z MY;Z MY;Z MY;Z MY;Z NV "
4508  "*XMW AY -[ 3ZHRH[\"aJRI` Fb 6a JW4W LW:W HX=W >WNX @Y !Z6Q VBV K"
4509  "P>SEW 9V>WAW>X3Z &W %W V #V 'X<X :X ;Z BY 4X )Y IW9X AY ;Y8Y 2Y .d 1d >U?"
4510  "ZH^MZ<X.X%X5Y NY.R&X2Z&X -X *Y/X+X/X'X -X -X;[ MX -X&X0X9a$Z3Y(X *Y3Y(X4X$P-Y @X :Y5Y GXNX"
4511  " <XNV9VNX2X9Y AX <Z /W #V *W EX:Z JZ9X NX .X9Z MX +W .X;[ MW6W MW ,W ,WBY CW ,W7W7W="
4512  "W6W NX9Y LZ9X X9Z MW AW FW +W:Z DWLW :^@^$XDY <WNW @Z LW :V MW ;\\@['X>\\ JX8X\"W?W AX"
4513  "9Y X *W6W CVNX ?X;X JX9Y NW@[@W/XFWFX NW=W IXEWEX!Z8X!X8W ;W ;W;X MX.X\"Y 1X 'Y9Y Lt\"X0X ?X"
4514  " @Y3Y MT HV IT Dj ET3T EYNVNY X 0XDS 6X 6ZM`LY >X :V LY 7T)T (UCU ET(T "
4515  " JX9Y :UGU ,UCU )V;m.V3V NV;mCY7P HX.X(X.X(X.X(X.X(X.X(X.X(X6X IY.R&X -X -X -X -"
4516  "X -X -X -X ,X2Z'X9a$Z3Y&Z3Y&Z3Y&Z3Y&Z3Y!Z9Z&Z3Y&Y5Y#Y5Y#Y5Y#Y5Y EX <X -W3W$X:Z MX:Z MX:Z M"
4517  "X:Z MX:Z MX:Z MX:^ NX -X -X -X -X -W ,W ,W ,W -X8X LW6W NX9Y MX9Y MX9Y MX9Y MX9Y 4Z H\\=Y K"
4518  "W:Z LW:Z LW:Z LW:Z CWNW ?Z9X DWNW :[@[ K[@[ K[@[ K[@[ K[@[ MV )WNX AX ,[ 1WGRFW "
4519  "N_IRH^ Da 5_ IW4W LX<X HW<W >` >Y !Y8S MX +VBV KQ?SFX 9V=VAV=Y6] &V &W"
4520  " NV BX 1X 1V 'Y>Y :X <Z BY 3X GP3Z IX;Y AX :Y9Z 2X GX -X 7a 1a .X 6V@iNa;X.X%X6Z N"
4521  "Z1T&X4\\&X -X *Z0X+X/X'X -X -X:[ NX -X&X0X9a#Z5Z(X *Z5Z(X4Y%R/Y @X 9Y7Y EWNW :WNV9VNW2Y9Y A"
4522  "X =Z .W #V *W EX;[ J[;X MY .X;[ MY2P JW .Y=\\ MW6W MW ,W ,WAY DW ,W7W7W=W6W MX:X K[;X"
4523  " MX;[ MW /P4X FX ,X<[ DXNX :^@^%XBX <` @Y KW :V MW 8V;W%X?^ KY9X!V@X @X:X NX *W6W C_"
4524  " >X:W JY;Z NXB]BX.XGWGX MW=W HXFWFX [:X NX:X ;W :W<W LX.X\"Y 1X &Y;Y Ip X0X ?X @Z5Z LR GV "
4525  " HR Bh CR1R Cj NX 0YES 6X 7ZJ\\IY ?X :V KY 8U+U 'TBT DU+T IY;Z :UGU "
4526  " ,TBT (V;m.V4V MV;mCY8Q HX.X(X.X(X.X(X.X(X.X(X.X)X5X IZ1T&X -X -X -X -X -X -X -X ,X4\\'"
4527  "X9a#Z5Z%Z5Z%Z5Z%Z5Z%Z5Z\"Z7Z&Z5Z%Y7Y!Y7Y!Y7Y!Y7Y DX <X -W4X$X;[ MX;[ MX;[ MX;[ MX;[ MX;[ MX"
4528  ";`3P=Y .Y2P LY2P LY2P LY2P LW ,W ,W ,W ,X:X KW6W MX:X KX:X KX:X KX:X KX:X 3Z GZ<X JX<[ LX<"
4529  "[ LX<[ LX<[ C` ?[;X C` 9_J_ I_J_ I_J_ I_J_ I_J_ LV )` AX +Z S <[GRFZ A_ 4^ HW4W"
4530  " KX>X HX<X ?` =Z \"Y:T MX +VCV JSASFX :V<VAV<Y8_ 'W 'W NV BX 1X 2W"
4531  " &X>X 9X =Z 1P2Z 3X GQ5Z GX=Y @X 9Y:Y KP8Z GX -X 4^ 1^ +X 5U?gM_9W,W%X7Z L[4U&X6]%X -X )"
4532  "[2X+X/X'X -X -X9[ X -X&X0X8`\"Z7Z'X )Z7Z'X3X%T2Y ?X 9Z9Z E` :_9_3Y7Y BX >Z -W #W +W D"
4533  "X=\\ J\\=Y LY7P HY=\\ LY5R JW -Y?] MW6W MW ,W ,W@Y EW ,W7W7W=W6W MY<Y K\\=Y MY=\\ MW /R6W DW ,Y"
4534  "=[ CWNW 9^@^&X@X <^ @Y JW :V MW HXA` LZ;X V@W ?Y<Y MX +W6W B^ ?X9W JZ<Z NXB]BX.YHW"
4535  "HY MW=W HYGWGY \\<Y NY<X :W :X>X LX.X#Y 0X %Y=Z Gl MX0X ?X ?Z7Z JP FV GP @f AP/P Ah MX "
4536  "/YFSDP BX 8ZFVEY @X :V JX 7V.U %SAS CU.U HZ<Z :UGU ,SAS (V:m/V5W"
4537  " MV:mBY;S HW,W(W,W(W,W(W,W(W,W(X.X)X5X H[4U&X -X -X -X -X -X -X -X ,X6]&X8`\"Z7Z#Z7Z#Z7Z#Z7"
4538  "Z#Z7Z\"Z5Z&[8Z$Z9Z!Z9Z!Z9Z!Z9Z DX <X -W4W\"X=\\ LX=\\ LX=\\ LX=\\ LX=\\ LX=\\ LX=b6R<Y7P GY5R KY5R"
4539  " KY5R KY5R LW ,W ,W ,W ,Y<Y KW6W MY<Y KY<Y KY<Y KY<Y KY<Y 3Z GY<Y JY=[ LY=[ LY=[ LY=[ B^ >"
4540  "\\=Y B^ 7r Gr Gr Gr Gr KV (_ BX )Y S 8RBSCR <] 2\\ GW4W KZBZ HX;W >_ <[ "
4541  " $[=U MX ,VBV JUCSHY :V;WCW<[<b (W 'W NV BX 1X 2W &Y@Y 9X >Z 0R5Z 2X GT9[ G"
4542  "Y?Z AY 9[>[ KR;Z FX -X 1[ 1[ (X 5V>dL^9X,X&X9[ J[7W&X9_$X -X (\\6Z+X/X'X -X -X8[!X -X&X0X"
4543  "8`![;[&X ([;[&X3Y&W7[ ?X 8Z;Z D` :^7^3X5Y CX ?Z ,W #W +W DY?] J]?Y KZ:R GY?] LZ8T JW"
4544  " -ZA^ MW6W MW ,W ,W?Y FW ,W7W7W=W6W LY>Y J]?Y KY?] MW /T9X DX ,Y@] CWNW 9]>]'Y@Y =^ AY IW"
4545  " :V MW HYCXNW L\\>Y VAX >Y>Y LY ,W6W B] >X9X K[>[ MXDVMVDX,YIWIY LW=W GYHWHY N]>Y LY"
4546  ">Y :X :X@X LX,X%Y /X $ZAZ Ch KX0X ?X >[;[ ?V 6d >f LX /[HSFR BX 9Z3Y AX :V IX 7"
4547  "V1V #R@R BU0U G[>[ :UGU ,R@R 'V(U)V6W LV(U<Z>U IX,X*X,X*X,X*X,X*X,X"
4548  "*X,X*W4X G[7W&X -X -X -X -X -X -X -X ,X9_%X8`![;[![;[![;[![;[![;[\"Z3Z(];[\"Z;Z NZ;Z NZ;Z NZ"
4549  ";Z CX <X -WJP;X\"Y?] LY?] LY?] LY?] LY?] LY?] LY?XNZ9T<Z:R GZ8T KZ8T KZ8T KZ8T LW ,W ,W ,W "
4550  "+Y>Y JW6W LY>Y IY>Y IY>Y IY>Y IY>Y 2Z FY>Y HY@] KY@] KY@] KY@] B^ >]?Y A^ 6o Do Do Do "
4551  "Do IV (_ CX (Y S (S ,[ 0[ GW4W J\\H\\ GW:W >^ :\\ %[@W MX ,VBV JXFS"
4552  "IZ :V:WEW:\\@e (V 'V MV BX 1X 2V $ZDZ 8X ?Z /U;] 2X GV=\\ EZC[ @X 7[@[ JT?[ EX -X /Y "
4553  " 1Y &X 5V=bK\\7X,X&X<^ I]=Z&X=b#X -X ']:\\+X/X'X -X -X7[\"X -X&X0X7_ \\?\\%X '\\?\\%X2X&Z<\\ >X 7["
4554  "?[ B^ 9^7^4Y5Y CX ?Y +W \"V +W DZB_ J_CZ I[>T G[C_ K[=W JW ,\\GXNW MW6W MW ,W ,W>Y GW "
4555  ",W7W7W=W6W KZBZ I_CZ J[C_ MW /W>Z DZ .ZB^ C` 8\\>\\&X>Y =\\ AY HW :V MW GZFYNY N]AZ N"
4556  "WCX <ZBZ JZ:Q EW6W B] ?X7W K\\A^ NYFWMWFY,ZJWJY KW=X H[JWJ[ N_BZ JZBZ 8Y <ZDZ LX,X&Y .X #ZC"
4557  "Z >_ FX0X ?X =\\?\\ >V 5b <d KX .\\JSHT BX 8X2X @X :V IX 5V4U Q?Q AV4V "
4558  " F\\A^ ;UGU ,Q?Q 'V'U*V6W LV'U<[AW IX,X*X,X*X,X*X,X*X,X*X,X+X4X F]=Z&X -X -X -X"
4559  " -X -X -X -X ,X=b$X7_ \\?\\ N\\?\\ N\\?\\ N\\?\\ N\\?\\ X1X(`?\\ [?[ L[?[ L[?[ L[?[ BX <X -WJS@Z\"ZB_ "
4560  "LZB_ LZB_ LZB_ LZB_ LZB_ LZBYM\\>W;[>T F[=W J[=W J[=W J[=W LW ,W ,W ,W *ZBZ IW6W KZBZ GZBZ "
4561  "GZBZ GZBZ GZBZ 1Z F[BZ GZB^ KZB^ KZB^ KZB^ A\\ =_CZ ?\\ 3l Al Al Al Al HV (^ BX (X "
4562  " NS (S ,Z .Y FW4W In GX:X ?^ 9_ (]FZ MX ,VBV J[ISL\\ :V9XGX9^Fi )W )W "
4563  " MV BX 1X 3W #[H[ Et Mx MZC_ 1X GZD^ C[G\\ @Y 7^F] IXF] DX -X ,V 1V #X 4V<^IY5X*X'y G"
4564  "_D^&{!y NX &`B`+X/X'X -X -X6[#w LX&X0X7_ N^E^$X &^E^$X2Y'^C^ =X 7^E^ B^ 8]7]4Y3Y DX @~U&W "
4565  "\"W ,W C\\HYNW JWNXG\\ H]EX F\\GXNW J]D[ JW +kMW MW6W MW ,W ,W=Y HW ,W7W7W=W6W K]H] IWNX"
4566  "G\\ I\\GXNW MW /[E\\ Be 9[GXNW B^ 7\\>\\'X<X =\\ AX GW :V MW G\\IYM^$`F\\ MWEX ;]H] J]BV E"
4567  "W6W A\\ ?X7X L_GaKP#ZJYMYJZ*[LWL[ KW=Y H\\LWL\\ MWNXG] J]H\\ 7a C[H[ L~W'x MX 1iEi HX CX0X ?X "
4568  "<^E^ =V 4` :b JX -^MSLX Lz V0V ?X :V HW 4V7V MP>P @W8W 3~W :_GaKP"
4569  " @UGU ,P>P 'V&U+V6V KV&U;]GZ JX*X,X*X,X*X,X*X,X*X,Y,Y,X4y7_D^&y Ny Ny Ny NX -X -X -"
4570  "X ,{\"X7_ N^E^ L^E^ L^E^ L^E^ L^E^ MV/V(dE^ N^E^ L^E^ L^E^ L^E^ BX <X -WJWF[ \\HYNW K\\HYNW K"
4571  "\\HYNW K\\HYNW K\\HYNW K\\HYNW K\\H[K^E[:]EX E]D[ I]D[ I]D[ I]D[ LW ,W ,W ,W )[F[ HW6W K]H] G]H"
4572  "] G]H] G]H] G]H] 1Z F]G] F[GXNW J[GXNW J[GXNW J[GXNW A\\ =WNXG\\ ?\\ 1h =h =h =h =h FV ']"
4573  " AV &W T )T +X -X EW4W Hl FX9W ?^ 8~R Jp MX ,VCV It 9V8XIX7sLZ "
4574  "*W )W MV BX 1X 3W #n Et Mx Mu 0X Gs Ao @X 5t In CX -X )S 1S X 4V9XFU1X*X'x Ex&z y "
4575  "NX %|*X/X'X -X -X5[$w LX&X0X6^ Mu#X %u#X1X'y =X 6u A^ 8]7]4X1X DX @~U&W \"W ,W ClMW J"
4576  "WMk Fo EkMW Is JW *jMW MW6W MW ,W ,W<Y IW ,W7W7W=W6W Jp HWMk GkMW MW /q Ae 9kMW B^ 7\\=[(Y;"
4577  "X >\\ Av 6W :V MW FkL]$u LXGX 9p Hp EW6W A[ ?X6X LpN\\#hKh)s JW<] Lu LWNm Hp 6` Bl K~"
4578  "W'x MX 1iEi HX CX0X ?X ;u <V 3^ 8` IX ,o Lz NT.T >X :V HW 3X=X )X<X 2"
4579  "~W :pN\\ @UGU V&U+V7i.V&U:o JX*X,X*X,X*X,X*X,X*X,X*X-X3y6x&y Ny Ny Ny NX -X "
4580  "-X -X ,z!X6^ Mu Ju Ju Ju Ju KT-T(} Lu Ju Ju Ju AX <X -WJk NlMW KlMW KlMW KlMW KlMW KlMW Kn"
4581  "Is9o Ds Hs Hs Hs LW ,W ,W ,W )p HW6W Jp Ep Ep Ep Ep Ls EkMW JkMW JkMW JkMW A\\ =WMk >\\ "
4582  " /c 8c 8c 8c 8c CV '\\ ?T %W U *T *W ,V DW4W Gj EW8W >\\ 5~P In LX "
4583  " -VBV Is 9V7g6qJZ *V )V LV BX 1X 3V !l Dt Mx Mt /X Gr ?m ?X 4r Hm BX -X &P 1P LX"
4584  " 3V 3X*X'w Cv%x My NX #x(X/X'X -X -X4[%w LX&X0X5] Ls\"X $s\"X1Y(w ;X 5s ?\\ 7\\5\\5Y1Y EX @~U&W"
4585  " !V ,W BjLW JWMj Dn DjMW Hr JW )hLW MW6W MW ,W ,W;Y JW ,W7W7W=W6W In GWMj EjMW MW /p"
4586  " ?d 8iLW B^ 6Z<[)Y:Y >Z @v 6W :V MW EiK]$t JYLZ 7n Fo EW6W A[ ?X5W LWNfM\\\"gKg'q IW<"
4587  "] Ks KWMk Fn 5` Aj J~W'x MX 1iEi HX CX0X ?X :s ;V 2\\ 6^ HX +n Lz MR,R =X :V HW "
4588  "1ZEZ %ZDZ 0~W :WNfM\\ @UGU !V%U,V6i/V%U9n JX*X,X*X,X*X,X*X,X*X,X*X-"
4589  "X3y5v%y Ny Ny Ny NX -X -X -X ,x NX5] Ls Hs Hs Hs Hs IR+R(WMs Js Hs Hs Hs @X <X -WJk MjLW J"
4590  "jLW JjLW JjLW JjLW JjLW JmHr8n Cr Gr Gr Gr LW ,W ,W ,W (n GW6W In Cn Cn Cn Cn Ls CiLW Ii"
4591  "LW IiLW IiLW @Z <WMj <Z +] 2] 2] 2] 2] @V &[ >R $V NU *U *U *U DW4W Fh DW8X ?\\ "
4592  "4~ Hl KX -VBV Hp 8V5e4nGZ +W +W LV BX 1X 3V j Ct Mx Mr -X Gq =j "
4593  ">Y 3p Gl AX -X 2X 3W 5X(X(u ?s$v Ky NX \"v'X/X'X -X -X3[&w LX&X0X5] Kq!X #p X0X(v :X "
4594  "4p =\\ 7\\5\\6Y/Y FX @~U&W !V ,W AhKW JWLh Bm ChLW Gq JW (eJW MW6W MW ,W ,W:Y KW ,W7W7W"
4595  "=W6W Hl FWLh ChLW MW /o >d 7gKW A\\ 5Z<Z(X8X >Z @v 6W :V MW DgI\\$s He 5l Dn EW6W @Y "
4596  ">W4X MWMeM\\!eIe%o HW<] Jq JWLi Dk 2_ @h J~Y(x MX 1iEi HX CX0X ?X 9q :V 1Z 4\\ GX *m"
4597  " Lz LP*P <X :V HW 0m \"l .~W :WMeM\\ @UGU !V%U,V6i/V%U8l JX(X.X(X"
4598  ".X(X.X(X.X(X.Y)X/X2y3s$y Ny Ny Ny NX -X -X -X ,v LX5] Kq Fq Fq Fq Fq GP)P'VKp Gp Ep Ep Ep "
4599  ">X <X -WJj KhKW IhKW IhKW IhKW IhKW IhKW IjEq7m Bq Fq Fq Fq LW ,W ,W ,W &j EW6W Hl Al Al A"
4600  "l Al Ls AgKW HgKW HgKW HgKW @Z <WLh ;Z MV &[ =P \"U V +V )S (S CW4W "
4601  "De DX8X ?\\ 2| Fh IX -VBV Ek 6V4c1kEZ +V +V KV BW 0X 4W Mf At Mx "
4602  "Mq ,X Go :h =X 0l Ej ?X -W 1X 2W 6X(X(s ;o\"s Hy NX r%X/X'X -X -X2['w LX&X0X4\\ Im NX"
4603  " !m NX0Y(t 9X 2m ;Z 5[5[5X-X FX @~U&W !W -W @fJW JWJe ?j AeJW En IW 'cIW MW6W MW ,W "
4604  ",W9Y LW ,W7W7W=W6W Fh DWJe AeJW MW .m ;b 6eJW A\\ 5Z<Z)X6X >X ?v 6W :V MW CeG[$r Fc "
4605  "2h Am EW6W @Y ?X3W MWMdL\\ cGc#m GW;\\ Hm HWKg Ah /] ?f I~Y(x MX 1iEi HX CX0X ?X 7m 8V 0"
4606  "X 2Z FX (j Kz AX :V HW -g Lh ,~W :WMdL\\ @UGU \"V$U-V5i0V$"
4607  "U7i HX(X.X(X.X(X.X(X.X(X.X(X/X2y1o\"y Ny Ny Ny NX -X -X -X ,t JX4\\ Im Bm Bm Bm Bm %VHm Dm "
4608  "Bm Bm Bm =X <X -WJh HfJW HfJW HfJW HfJW HfJW HfJW HhBn4j ?n Cn Cn Cn KW ,W ,W ,W %h DW6W F"
4609  "h =h =h =h =h KVMi >eJW GeJW GeJW GeJW ?X ;WJe 9X MW &Z =U W ,W *"
4610  "R &Q BW4W B` AW6W >[ /y Dd GX -VCV Af 5V2a.gBZ ,W -W KV CX 0X 4V "
4611  " Kd @t Mx Km *X Ek 6d ;X .h Bh >X .X 1X 1W 7X(X(q 7j Np Ey NX Mm\"X/X'X -X -X1[(w LX"
4612  "&X0X4\\ Gi LX Ni LX/X$n 7X 0i 9Z 5[5[6Y-Y GX @~U&W V -W >cIW JWIb <g =bIW Ci FW %_G"
4613  "W MW6W MW ,W ,W8Y MW ,W7W7W=W6W Ef CWIb =bIW MW +h 8a 5cIW @Z 4Y:Y*Y5X ?X ?v 6W :V MW "
4614  " AbDY$WMf Ca 0f >k EW6W @Y ?W2W MWK`I[ NaEa i EW;\\ Fi FWIc >e ,\\ =b G~Y(x MX 1iEi HX CX0"
4615  "X ?X 5i 6V /V 0X EX &f Iz AX :V /P;W *c Gb )~W :WK`I[ @UGU "
4616  " #V#U.V4i1V#U6f FX(X.X(X.X(X.X(X.X(X.X(X/X2y/j Ny Ny Ny Ny NX -X -X -X ,p FX4\\ Gi >i "
4617  ">i >i >i $VEi @i >i >i >i ;X <X -WIf EcIW FcIW FcIW FcIW FcIW FcIW Fd>i0g ;i >i >i >i HW "
4618  ",W ,W ,W #d BW6W Ef ;f ;f ;f ;f JUJe ;cIW FcIW FcIW FcIW ?X ;WIb 7X MW %Y "
4619  " =T X -X )P %P AW4W ?Z >W6X ?Z ,w B` EX .VBV <] 1V0]*b?[ -W -W"
4620  " KV CW /X 4V I` >t Mx Hg 'X Bf 2` :X +d =b ;X .W 0X 1X 9X&X)m 0d Kj ?y NX Jg "
4621  "NX/X'X -X -X0[)w LX&X0X3[ Dc IX Kf LX/Y!g 4X .e 7Z 5Z3Z7Y+Y HX @~U&W V -W =`GW JWG"
4622  "^ 7b 9^GW Ad CW \"YDW MW6W MW ,W ,W7Y NW ,W7W7W=W6W B` @WG^ 9^GW MW (c 2] 3_GW @Z 3X:X*Y4Y "
4623  "@X ?v 6W :V MW ?_AW$WKb @^ +` 9g CW6W ?W ?X2X NWJ^GY K]B^ Ke CW:[ Dd CWG_ 9` 'Y ;^ "
4624  "F~[)x MX 1iEi HX CX0X ?X 2c 3V .T .V DX $b Gz AX :V /R>X &[ ?Z %~W "
4625  " :WJ^GY ?UGU #V +V +V 1b EX&X0X&X0X&X0X&X0X&X0Y'X1X1y,d Ky Ny Ny Ny NX -X -X "
4626  "-X ,j @X3[ Dc 8c 8c 8c 8c !VBc ;e :e :e :e 9X <X -WFa B`GW E`GW E`GW E`GW E`GW E`GW D`:d*"
4627  "b 7d 9d 9d 9d EW ,W ,W ,W !` @W6W B` 5` 5` 5` 5` HVHa 7_GW D_GW D_GW D_GW ?X ;WG^ 5X "
4628  " MW 7S @r >Y BS .V,W#Z ;V -V "
4629  " 7W ;W EX ;\\ 6] +Z 5\\ 5Z <W 7X %\\ <] \"X ([ "
4630  " 4c E] /[ (W W .W :Y #X 0Z 2X *\\ $W &W .Z =WDX 3XDW I["
4631  " 0Y 8W -W :V MW <Z ;WH[ 9Y &Z 1] LW ?W >WGXBU FX=X E` \"W >] @WDY 3Z "
4632  "2X C[ >T :[ KV /TAY EWGXBU =UGU"
4633  " BT 6V +V +V ,Y ?\\ +[ 0[ 0[ 0[ 0[ KT=[ 2[ 0[ 0["
4634  " 0[ 7Z ;Y .Y .Y .Y .Y .Y -Y2\\\"Z /\\ 1\\ 1\\ 1\\ CZ 3Z /Z /Z /Z /Z FVCZ 1Y .Y ."
4635  "Y .Y ,W :WDX 2W LW 7R #S"
4636  " >W /W 8W :V \"W 5X )X "
4637  " &Z CW NV .W :W %W @W :W "
4638  " -X -W :V MW LW FW ?W >W NW 0W =W "
4639  " 3S GV /XGZ DW HUGU AT %"
4640  "T 'R JT "
4641  " #T (X :W NX LW "
4642  " 7S =V /V 7W :V \"W 4X'Q "
4643  "&Y %Z DW NV .W :W %W @W :W "
4644  " -W ,W :V MW LW FW ?W >W NW 0W =W "
4645  " 3S GV /j CW HUGU @T "
4646  " %T 'P HT "
4647  " \"Q 'W 9W NW KW "
4648  " 7S =W 1W 7V :W \"V 2X)R "
4649  " &X #Z EW NW /W :W %W "
4650  " @W :W -W ,X ;V NX LW FW ?W >W NW 0W =W "
4651  " 3S GV /j CW HUGU @U "
4652  " &U U "
4653  " \"P 'W 9W NW KV "
4654  " 6S <V 1V 6V :V !V 1Y-U "
4655  " 'X \"Z FW MV /W ;X %W "
4656  " @W :W .X +W ;V NW KW FW ?W >W NW 0W =W "
4657  " 3S GV /h AW HUGU ?T "
4658  " %T NT "
4659  " )X 9W X KV "
4660  " 6S <W 3V 6V 9V \"V "
4661  " /Z1X (X !Z Ga (V 9a ;W "
4662  "$W @W :W .W *W ;V NW KW FW ?W >W NW 0W =W"
4663  " 3S GV .f @W HUGU ?"
4664  "U &U "
4665  " U *W 8W W JV "
4666  " 6S ;V 3V 6V :W \"V "
4667  " .[5[ *Y Z Ha (W :a <X"
4668  " $W @W :W /X *X <V X KW FW ?W >W NW 0W"
4669  " =W 3S GV +a >W HUGU "
4670  " >T %T "
4671  " NT +X 8W !X (VIV "
4672  " 6S :V 5V 5U 9W \""
4673  "U +\\;] )X MZ Ia (W :a "
4674  " =Y %W ?W :W /W )[ ?V #[ KW FW ?W >W N"
4675  "W 0W =W 3S GV 'Z ;W "
4676  " HUGU >U &U "
4677  " U ,W 7W !W 'VIV "
4678  " 6S :V 6W 6V "
4679  " 4V *_C` )Y LZ Ja :a "
4680  " (P7Y $W ?W :W 0X (b GV +b JW FW ?W >W "
4681  " NW 0W =W 3S GV "
4682  "7W HUGU >U &U "
4683  " U -X 7W \"X 'VJW "
4684  " 6S 9V 7V 5U "
4685  " 3U 'x (Z KZ Ka :a "
4686  " (R:Z $W ?W :W 0X (b GV +b JW FW ?W >W"
4687  " NW 0W =W 3S GV "
4688  " 7W #U &U "
4689  " U -X 7W \"X &UJW "
4690  " 6S 9W 9W "
4691  " Bu ([ IZ La :a "
4692  " (T>[ $X ?W :W 1X &a GV +a IW FW ?W >W N"
4693  "W 0W =W 3S GV 7W "
4694  " $V 'V "
4695  " !V .X 6W #X %VLW "
4696  " 5S "
4697  " 2p -a 8XE] %Y"
4698  " >W :W 3Z $_ GV +_ GW FW ?W >W NW 0W =W "
4699  " 3S GV 7W /QGW "
4700  " 2QGW ,QG"
4701  "W 0Z 6W %Z %a "
4702  " 5S 0l "
4703  " +a 8p +_ "
4704  " >W :W ;a !] GV +] EW FW ?W >W NW 0W =W "
4705  " 3S GV 7W /` "
4706  " 1` +` "
4707  " 7a 5W -a #` "
4708  " >e '`"
4709  " 7o *^ =W :W "
4710  " ;` KY GV +Y AW FW ?W >W NW 0W =W "
4711  " 3S GV 7W /` 1` "
4712  " +` "
4713  " 7` 4W -` \"_ "
4714  " 8\\ #_ "
4715  " \"} 3n )^ =W :W ;` 9V "
4716  " BW FW ?W >W NW 0W =W 'V "
4717  " 7W /_ 0_ "
4718  " *_ 6` 4W -` "
4719  " !] "
4720  " -] "
4721  " } 3l '] <W :W ;_ 8V BW FW ?"
4722  "W >W NW 0W =W 'V "
4723  " 7W /^ /^ "
4724  " )^ 5_ 3W -_ N[ "
4725  " "
4726  " ,[ M} 2j "
4727  " &\\ ;W :W ;^ 7V BW FW ?W >W NW 0W =W"
4728  " 7W -Y "
4729  " *Y $Y "
4730  " 2^ 2W -^ LX "
4731  " "
4732  " *X J} /d #Z 9W :"
4733  "W ;\\ 5V BW FW ?W >W NW 0W =W "
4734  " 7W "
4735  " "
4736  " /\\ 0W HT "
4737  " "
4738  " I} *[ NW 6W :W ;Z 3V "
4739  " BW FW ?W >W NW 0W =W "
4740  " 7W "
4741  " /Z .W "
4742  " "
4743  " =} "
4744  " "
4745  " "
4746  " "
4747  " D" };
4748 
4749  // Define a 40x38 'danger' color logo (used by cimg::dialog()).
4750  static const unsigned char logo40x38[4576] = {
4751  177,200,200,200,3,123,123,0,36,200,200,200,1,123,123,0,2,255,255,0,1,189,189,189,1,0,0,0,34,200,200,200,
4752  1,123,123,0,4,255,255,0,1,189,189,189,1,0,0,0,1,123,123,123,32,200,200,200,1,123,123,0,5,255,255,0,1,0,0,
4753  0,2,123,123,123,30,200,200,200,1,123,123,0,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,29,200,200,200,
4754  1,123,123,0,7,255,255,0,1,0,0,0,2,123,123,123,28,200,200,200,1,123,123,0,8,255,255,0,1,189,189,189,1,0,0,0,
4755  2,123,123,123,27,200,200,200,1,123,123,0,9,255,255,0,1,0,0,0,2,123,123,123,26,200,200,200,1,123,123,0,10,255,
4756  255,0,1,189,189,189,1,0,0,0,2,123,123,123,25,200,200,200,1,123,123,0,3,255,255,0,1,189,189,189,3,0,0,0,1,189,
4757  189,189,3,255,255,0,1,0,0,0,2,123,123,123,24,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,3,255,255,0,1,189,
4758  189,189,1,0,0,0,2,123,123,123,23,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,4,255,255,0,1,0,0,0,2,123,123,123,
4759  22,200,200,200,1,123,123,0,5,255,255,0,5,0,0,0,4,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,21,200,200,200,
4760  1,123,123,0,5,255,255,0,5,0,0,0,5,255,255,0,1,0,0,0,2,123,123,123,20,200,200,200,1,123,123,0,6,255,255,0,5,0,0,
4761  0,5,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,19,200,200,200,1,123,123,0,6,255,255,0,1,123,123,0,3,0,0,0,1,
4762  123,123,0,6,255,255,0,1,0,0,0,2,123,123,123,18,200,200,200,1,123,123,0,7,255,255,0,1,189,189,189,3,0,0,0,1,189,
4763  189,189,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,17,200,200,200,1,123,123,0,8,255,255,0,3,0,0,0,8,255,255,
4764  0,1,0,0,0,2,123,123,123,16,200,200,200,1,123,123,0,9,255,255,0,1,123,123,0,1,0,0,0,1,123,123,0,8,255,255,0,1,189,
4765  189,189,1,0,0,0,2,123,123,123,15,200,200,200,1,123,123,0,9,255,255,0,1,189,189,189,1,0,0,0,1,189,189,189,9,255,
4766  255,0,1,0,0,0,2,123,123,123,14,200,200,200,1,123,123,0,11,255,255,0,1,0,0,0,10,255,255,0,1,189,189,189,1,0,0,0,2,
4767  123,123,123,13,200,200,200,1,123,123,0,23,255,255,0,1,0,0,0,2,123,123,123,12,200,200,200,1,123,123,0,11,255,255,0,
4768  1,189,189,189,2,0,0,0,1,189,189,189,9,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,11,200,200,200,1,123,123,0,11,
4769  255,255,0,4,0,0,0,10,255,255,0,1,0,0,0,2,123,123,123,10,200,200,200,1,123,123,0,12,255,255,0,4,0,0,0,10,255,255,0,
4770  1,189,189,189,1,0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,12,255,255,0,1,189,189,189,2,0,0,0,1,189,189,189,11,
4771  255,255,0,1,0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,27,255,255,0,1,0,0,0,3,123,123,123,8,200,200,200,1,123,
4772  123,0,26,255,255,0,1,189,189,189,1,0,0,0,3,123,123,123,9,200,200,200,1,123,123,0,24,255,255,0,1,189,189,189,1,0,0,
4773  0,4,123,123,123,10,200,200,200,1,123,123,0,24,0,0,0,5,123,123,123,12,200,200,200,27,123,123,123,14,200,200,200,25,
4774  123,123,123,86,200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0 };
4775 
4777 
4781  inline std::FILE* output(std::FILE *file) {
4782  cimg::mutex(1);
4783  static std::FILE *res = cimg::_stderr();
4784  if (file) res = file;
4785  cimg::mutex(1,0);
4786  return res;
4787  }
4788 
4789  // Return number of available CPU cores.
4790  inline unsigned int nb_cpus() {
4791  unsigned int res = 1;
4792 #if cimg_OS==2
4793  SYSTEM_INFO sysinfo;
4794  GetSystemInfo(&sysinfo);
4795  res = (unsigned int)sysinfo.dwNumberOfProcessors;
4796 #elif cimg_OS == 1
4797  res = (unsigned int)sysconf(_SC_NPROCESSORS_ONLN);
4798 #endif
4799  return res?res:1U;
4800  }
4801 
4802  // Lock/unlock mutex for CImg multi-thread programming.
4803  inline int mutex(const unsigned int n, const int lock_mode) {
4804  switch (lock_mode) {
4805  case 0 : cimg::Mutex_attr().unlock(n); return 0;
4806  case 1 : cimg::Mutex_attr().lock(n); return 0;
4807  default : return cimg::Mutex_attr().trylock(n);
4808  }
4809  }
4810 
4812 
4826  inline void warn(const char *const format, ...) {
4827  if (cimg::exception_mode()>=1) {
4828  char *const message = new char[16384];
4829  std::va_list ap;
4830  va_start(ap,format);
4831  cimg_vsnprintf(message,16384,format,ap);
4832  va_end(ap);
4833 #ifdef cimg_strict_warnings
4834  throw CImgWarningException(message);
4835 #else
4836  std::fprintf(cimg::output(),"\n%s[CImg] *** Warning ***%s%s\n",cimg::t_red,cimg::t_normal,message);
4837 #endif
4838  delete[] message;
4839  }
4840  }
4841 
4842  // Execute an external system command.
4851  inline int system(const char *const command, const char *const module_name=0, const bool is_verbose=false) {
4852  cimg::unused(module_name);
4853 #ifdef cimg_no_system_calls
4854  return -1;
4855 #else
4856  if (is_verbose) return std::system(command);
4857 #if cimg_OS==1
4858  const unsigned int l = (unsigned int)std::strlen(command);
4859  if (l) {
4860  char *const ncommand = new char[l + 24];
4861  std::strncpy(ncommand,command,l);
4862  std::strcpy(ncommand + l," >/dev/null 2>&1"); // Make command silent.
4863  const int out_val = std::system(ncommand);
4864  delete[] ncommand;
4865  return out_val;
4866  } else return -1;
4867 #elif cimg_OS==2
4868  PROCESS_INFORMATION pi;
4869  STARTUPINFO si;
4870  std::memset(&pi,0,sizeof(PROCESS_INFORMATION));
4871  std::memset(&si,0,sizeof(STARTUPINFO));
4872  GetStartupInfo(&si);
4873  si.cb = sizeof(si);
4874  si.wShowWindow = SW_HIDE;
4875  si.dwFlags |= SW_HIDE | STARTF_USESHOWWINDOW;
4876  const BOOL res = CreateProcess((LPCTSTR)module_name,(LPTSTR)command,0,0,FALSE,0,0,0,&si,&pi);
4877  if (res) {
4878  WaitForSingleObject(pi.hProcess,INFINITE);
4879  CloseHandle(pi.hThread);
4880  CloseHandle(pi.hProcess);
4881  return 0;
4882  } else return std::system(command);
4883 #else
4884  return std::system(command);
4885 #endif
4886 #endif
4887  }
4888 
4890  template<typename T>
4891  inline T& temporary(const T&) {
4892  static T temp;
4893  return temp;
4894  }
4895 
4897  template<typename T>
4898  inline void swap(T& a, T& b) { T t = a; a = b; b = t; }
4899 
4901  template<typename T1, typename T2>
4902  inline void swap(T1& a1, T1& b1, T2& a2, T2& b2) {
4903  cimg::swap(a1,b1); cimg::swap(a2,b2);
4904  }
4905 
4907  template<typename T1, typename T2, typename T3>
4908  inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3) {
4909  cimg::swap(a1,b1,a2,b2); cimg::swap(a3,b3);
4910  }
4911 
4913  template<typename T1, typename T2, typename T3, typename T4>
4914  inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4) {
4915  cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4);
4916  }
4917 
4919  template<typename T1, typename T2, typename T3, typename T4, typename T5>
4920  inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5) {
4921  cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5);
4922  }
4923 
4925  template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
4926  inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6) {
4927  cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); cimg::swap(a6,b6);
4928  }
4929 
4931  template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
4932  inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6,
4933  T7& a7, T7& b7) {
4934  cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6); cimg::swap(a7,b7);
4935  }
4936 
4938  template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
4939  inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6,
4940  T7& a7, T7& b7, T8& a8, T8& b8) {
4941  cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6,a7,b7); cimg::swap(a8,b8);
4942  }
4943 
4945 
4948  inline bool endianness() {
4949  const int x = 1;
4950  return ((unsigned char*)&x)[0]?false:true;
4951  }
4952 
4954 
4958  template<typename T>
4959  inline void invert_endianness(T* const buffer, const cimg_ulong size) {
4960  if (size) switch (sizeof(T)) {
4961  case 1 : break;
4962  case 2 : {
4963  for (unsigned short *ptr = (unsigned short*)buffer + size; ptr>(unsigned short*)buffer; ) {
4964  const unsigned short val = *(--ptr);
4965  *ptr = (unsigned short)((val>>8) | ((val<<8)));
4966  }
4967  } break;
4968  case 4 : {
4969  for (unsigned int *ptr = (unsigned int*)buffer + size; ptr>(unsigned int*)buffer; ) {
4970  const unsigned int val = *(--ptr);
4971  *ptr = (val>>24) | ((val>>8)&0xff00) | ((val<<8)&0xff0000) | (val<<24);
4972  }
4973  } break;
4974  case 8 : {
4975  const cimg_uint64
4976  m0 = (cimg_uint64)0xff, m1 = m0<<8, m2 = m0<<16, m3 = m0<<24,
4977  m4 = m0<<32, m5 = m0<<40, m6 = m0<<48, m7 = m0<<56;
4978  for (cimg_uint64 *ptr = (cimg_uint64*)buffer + size; ptr>(cimg_uint64*)buffer; ) {
4979  const cimg_uint64 val = *(--ptr);
4980  *ptr = (((val&m7)>>56) | ((val&m6)>>40) | ((val&m5)>>24) | ((val&m4)>>8) |
4981  ((val&m3)<<8) |((val&m2)<<24) | ((val&m1)<<40) | ((val&m0)<<56));
4982  }
4983  } break;
4984  default : {
4985  for (T* ptr = buffer + size; ptr>buffer; ) {
4986  unsigned char *pb = (unsigned char*)(--ptr), *pe = pb + sizeof(T);
4987  for (int i = 0; i<(int)sizeof(T)/2; ++i) swap(*(pb++),*(--pe));
4988  }
4989  }
4990  }
4991  }
4992 
4994 
4998  template<typename T>
4999  inline T& invert_endianness(T& a) {
5000  invert_endianness(&a,1);
5001  return a;
5002  }
5003 
5004  // Conversion functions to get more precision when trying to store unsigned ints values as floats.
5005  inline unsigned int float2uint(const float f) {
5006  int tmp = 0;
5007  std::memcpy(&tmp,&f,sizeof(float));
5008  if (tmp>=0) return (unsigned int)f;
5009  unsigned int u;
5010  // use memcpy instead of assignment to avoid undesired optimizations by C++-compiler.
5011  std::memcpy(&u,&f,sizeof(float));
5012  return ((u)<<1)>>1; // set sign bit to 0.
5013  }
5014 
5015  inline float uint2float(const unsigned int u) {
5016  if (u<(1U<<19)) return (float)u; // Consider safe storage of unsigned int as floats until 19bits (i.e 524287).
5017  float f;
5018  const unsigned int v = u|(1U<<(8*sizeof(unsigned int)-1)); // set sign bit to 1.
5019  // use memcpy instead of simple assignment to avoid undesired optimizations by C++-compiler.
5020  std::memcpy(&f,&v,sizeof(float));
5021  return f;
5022  }
5023 
5025 
5028  inline cimg_ulong time() {
5029 #if cimg_OS==1
5030  struct timeval st_time;
5031  gettimeofday(&st_time,0);
5032  return (cimg_ulong)(st_time.tv_usec/1000 + st_time.tv_sec*1000);
5033 #elif cimg_OS==2
5034  SYSTEMTIME st_time;
5035  GetLocalTime(&st_time);
5036  return (cimg_ulong)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour)));
5037 #else
5038  return 0;
5039 #endif
5040  }
5041 
5042  // Implement a tic/toc mechanism to display elapsed time of algorithms.
5043  inline cimg_ulong tictoc(const bool is_tic);
5044 
5046 
5049  inline cimg_ulong tic() {
5050  return cimg::tictoc(true);
5051  }
5052 
5054 
5057  inline cimg_ulong toc() {
5058  return cimg::tictoc(false);
5059  }
5060 
5062 
5067  inline void sleep(const unsigned int milliseconds) {
5068 #if cimg_OS==1
5069  struct timespec tv;
5070  tv.tv_sec = milliseconds/1000;
5071  tv.tv_nsec = (milliseconds%1000)*1000000;
5072  nanosleep(&tv,0);
5073 #elif cimg_OS==2
5074  Sleep(milliseconds);
5075 #else
5076  cimg::unused(milliseconds);
5077 #endif
5078  }
5079 
5080  inline unsigned int _wait(const unsigned int milliseconds, cimg_ulong& timer) {
5081  if (!timer) timer = cimg::time();
5082  const cimg_ulong current_time = cimg::time();
5083  if (current_time>=timer + milliseconds) { timer = current_time; return 0; }
5084  const unsigned int time_diff = (unsigned int)(timer + milliseconds - current_time);
5085  timer = current_time + time_diff;
5086  cimg::sleep(time_diff);
5087  return time_diff;
5088  }
5089 
5091 
5097  inline cimg_long wait(const unsigned int milliseconds) {
5098  cimg::mutex(3);
5099  static cimg_ulong timer = 0;
5100  if (!timer) timer = cimg::time();
5101  cimg::mutex(3,0);
5102  return _wait(milliseconds,timer);
5103  }
5104 
5105  // Random number generators.
5106  // CImg may use its own Random Number Generator (RNG) if configuration macro 'cimg_use_rng' is set.
5107  // Use it for instance when you have to deal with concurrent threads trying to call std::srand()
5108  // at the same time!
5109 #ifdef cimg_use_rng
5110 
5111 #include <stdint.h>
5112 
5113  // Use a custom RNG.
5114  inline unsigned int _rand(const unsigned int seed=0, const bool set_seed=false) {
5115  static cimg_ulong next = 0xB16B00B5;
5116  cimg::mutex(4);
5117  if (set_seed) next = (cimg_ulong)seed;
5118  else next = next*1103515245 + 12345U;
5119  cimg::mutex(4,0);
5120  return (unsigned int)(next&0xFFFFFFU);
5121  }
5122 
5123  inline unsigned int srand() {
5124  unsigned int t = (unsigned int)cimg::time();
5125 #if cimg_OS==1
5126  t+=(unsigned int)getpid();
5127 #elif cimg_OS==2
5128  t+=(unsigned int)_getpid();
5129 #endif
5130  return cimg::_rand(t,true);
5131  }
5132 
5133  inline unsigned int srand(const unsigned int seed) {
5134  return _rand(seed,true);
5135  }
5136 
5137  inline double rand(const double val_min, const double val_max) {
5138  const double val = cimg::_rand()/16777215.;
5139  return val_min + (val_max - val_min)*val;
5140  }
5141 
5142 #else
5143 
5144  // Use the system RNG.
5145  inline unsigned int srand() {
5146  const unsigned int t = (unsigned int)cimg::time();
5147 #if cimg_OS==1 || defined(__BORLANDC__)
5148  std::srand(t + (unsigned int)getpid());
5149 #elif cimg_OS==2
5150  std::srand(t + (unsigned int)_getpid());
5151 #else
5152  std::srand(t);
5153 #endif
5154  return t;
5155  }
5156 
5157  inline unsigned int srand(const unsigned int seed) {
5158  std::srand(seed);
5159  return seed;
5160  }
5161 
5163 
5165  inline double rand(const double val_min, const double val_max) {
5166  const double val = (double)std::rand()/RAND_MAX;
5167  return val_min + (val_max - val_min)*val;
5168  }
5169 #endif
5170 
5172 
5174  inline double rand(const double val_max=1) {
5175  return cimg::rand(0,val_max);
5176  }
5177 
5179 
5181  inline double grand() {
5182  double x1, w;
5183  do {
5184  const double x2 = cimg::rand(-1,1);
5185  x1 = cimg::rand(-1,1);
5186  w = x1*x1 + x2*x2;
5187  } while (w<=0 || w>=1.0);
5188  return x1*std::sqrt((-2*std::log(w))/w);
5189  }
5190 
5192 
5194  inline unsigned int prand(const double z) {
5195  if (z<=1.0e-10) return 0;
5196  if (z>100) return (unsigned int)((std::sqrt(z) * cimg::grand()) + z);
5197  unsigned int k = 0;
5198  const double y = std::exp(-z);
5199  for (double s = 1.0; s>=y; ++k) s*=cimg::rand();
5200  return k - 1;
5201  }
5202 
5204  template<typename T, typename t>
5205  inline T cut(const T& val, const t& val_min, const t& val_max) {
5206  return val<val_min?(T)val_min:val>val_max?(T)val_max:val;
5207  }
5208 
5210  template<typename T>
5211  inline T rol(const T& a, const unsigned int n=1) {
5212  return n?(T)((a<<n)|(a>>((sizeof(T)<<3) - n))):a;
5213  }
5214 
5215  inline float rol(const float a, const unsigned int n=1) {
5216  return (float)rol((int)a,n);
5217  }
5218 
5219  inline double rol(const double a, const unsigned int n=1) {
5220  return (double)rol((cimg_long)a,n);
5221  }
5222 
5223  inline double rol(const long double a, const unsigned int n=1) {
5224  return (double)rol((cimg_long)a,n);
5225  }
5226 
5227 #ifdef cimg_use_half
5228  inline half rol(const half a, const unsigned int n=1) {
5229  return (half)rol((int)a,n);
5230  }
5231 #endif
5232 
5234  template<typename T>
5235  inline T ror(const T& a, const unsigned int n=1) {
5236  return n?(T)((a>>n)|(a<<((sizeof(T)<<3) - n))):a;
5237  }
5238 
5239  inline float ror(const float a, const unsigned int n=1) {
5240  return (float)ror((int)a,n);
5241  }
5242 
5243  inline double ror(const double a, const unsigned int n=1) {
5244  return (double)ror((cimg_long)a,n);
5245  }
5246 
5247  inline double ror(const long double a, const unsigned int n=1) {
5248  return (double)ror((cimg_long)a,n);
5249  }
5250 
5251 #ifdef cimg_use_half
5252  inline half ror(const half a, const unsigned int n=1) {
5253  return (half)ror((int)a,n);
5254  }
5255 #endif
5256 
5258  template<typename T>
5259  inline T abs(const T& a) {
5260  return a>=0?a:-a;
5261  }
5262  inline bool abs(const bool a) {
5263  return a;
5264  }
5265  inline int abs(const unsigned char a) {
5266  return (int)a;
5267  }
5268  inline int abs(const unsigned short a) {
5269  return (int)a;
5270  }
5271  inline int abs(const unsigned int a) {
5272  return (int)a;
5273  }
5274  inline int abs(const int a) {
5275  return std::abs(a);
5276  }
5277  inline cimg_int64 abs(const cimg_uint64 a) {
5278  return (cimg_int64)a;
5279  }
5280  inline double abs(const double a) {
5281  return std::fabs(a);
5282  }
5283  inline float abs(const float a) {
5284  return (float)std::fabs((double)a);
5285  }
5286 
5288  template<typename T>
5289  inline T sqr(const T& val) {
5290  return val*val;
5291  }
5292 
5294  inline int xln(const int x) {
5295  return x>0?(int)(1 + std::log10((double)x)):1;
5296  }
5297 
5299  template<typename t>
5300  inline t min(const t& a, const t& b, const t& c) {
5301  return std::min(std::min(a,b),c);
5302  }
5303 
5305  template<typename t>
5306  inline t min(const t& a, const t& b, const t& c, const t& d) {
5307  return std::min(std::min(a,b),std::min(c,d));
5308  }
5309 
5311  template<typename t>
5312  inline t max(const t& a, const t& b, const t& c) {
5313  return std::max(std::max(a,b),c);
5314  }
5315 
5317  template<typename t>
5318  inline t max(const t& a, const t& b, const t& c, const t& d) {
5319  return std::max(std::max(a,b),std::max(c,d));
5320  }
5321 
5323  template<typename T>
5324  inline T sign(const T& x) {
5325  return (T)(x<0?-1:x>0);
5326  }
5327 
5329  template<typename T>
5330  inline cimg_ulong nearest_pow2(const T& x) {
5331  cimg_ulong i = 1;
5332  while (x>i) i<<=1;
5333  return i;
5334  }
5335 
5337  inline double sinc(const double x) {
5338  return x?std::sin(x)/x:1;
5339  }
5340 
5342 
5347  template<typename T>
5348  inline T mod(const T& x, const T& m) {
5349  const double dx = (double)x, dm = (double)m;
5350  return (T)(dx - dm * std::floor(dx / dm));
5351  }
5352  inline int mod(const bool x, const bool m) {
5353  return m?(x?1:0):0;
5354  }
5355  inline int mod(const unsigned char x, const unsigned char m) {
5356  return x%m;
5357  }
5358  inline int mod(const char x, const char m) {
5359 #if defined(CHAR_MAX) && CHAR_MAX==255
5360  return x%m;
5361 #else
5362  return x>=0?x%m:(x%m?m + x%m:0);
5363 #endif
5364  }
5365  inline int mod(const unsigned short x, const unsigned short m) {
5366  return x%m;
5367  }
5368  inline int mod(const short x, const short m) {
5369  return x>=0?x%m:(x%m?m + x%m:0);
5370  }
5371  inline int mod(const unsigned int x, const unsigned int m) {
5372  return (int)(x%m);
5373  }
5374  inline int mod(const int x, const int m) {
5375  return x>=0?x%m:(x%m?m + x%m:0);
5376  }
5377  inline cimg_int64 mod(const cimg_uint64 x, const cimg_uint64 m) {
5378  return x%m;
5379  }
5380  inline cimg_int64 mod(const cimg_int64 x, const cimg_int64 m) {
5381  return x>=0?x%m:(x%m?m + x%m:0);
5382  }
5383 
5385 
5390  template<typename T>
5391  inline T minmod(const T& a, const T& b) {
5392  return a*b<=0?0:(a>0?(a<b?a:b):(a<b?b:a));
5393  }
5394 
5396  inline double log2(const double x) {
5397  const double base = std::log(2.0);
5398  return std::log(x)/base;
5399  }
5400 
5401  template<typename T>
5402  inline T round(const T& x) {
5403  return (T)std::floor((_cimg_Tfloat)x + 0.5f);
5404  }
5405 
5407 
5413  template<typename T>
5414  inline T round(const T& x, const double y, const int rounding_type=0) {
5415  if (y<=0) return x;
5416  if (y==1) switch (rounding_type) {
5417  case 0 : return round(x);
5418  case 1 : return (T)std::ceil((_cimg_Tfloat)x);
5419  default : return (T)std::floor((_cimg_Tfloat)x);
5420  }
5421  const double sx = (double)x/y, floor = std::floor(sx), delta = sx - floor;
5422  return (T)(y*(rounding_type<0?floor:rounding_type>0?std::ceil(sx):delta<0.5?floor:std::ceil(sx)));
5423  }
5424 
5426  template<typename T>
5427  inline double cbrt(const T& x) {
5428 #if cimg_use_cpp11==1
5429  return std::cbrt(x);
5430 #else
5431  return x>=0?std::pow((double)x,1.0/3):-std::pow(-(double)x,1.0/3);
5432 #endif
5433  }
5434 
5435  // Code to compute fast median from 2,3,5,7,9,13,25 and 49 values.
5436  // (contribution by RawTherapee: http://rawtherapee.com/).
5437  template<typename T>
5438  inline T median(T val0, T val1) {
5439  return (val0 + val1)/2;
5440  }
5441 
5442  template<typename T>
5443  inline T median(T val0, T val1, T val2) {
5444  return std::max(std::min(val0,val1),std::min(val2,std::max(val0,val1)));
5445  }
5446 
5447  template<typename T>
5448  inline T median(T val0, T val1, T val2, T val3, T val4) {
5449  T tmp = std::min(val0,val1);
5450  val1 = std::max(val0,val1); val0 = tmp; tmp = std::min(val3,val4); val4 = std::max(val3,val4);
5451  val3 = std::max(val0,tmp); val1 = std::min(val1,val4); tmp = std::min(val1,val2); val2 = std::max(val1,val2);
5452  val1 = tmp; tmp = std::min(val2,val3);
5453  return std::max(val1,tmp);
5454  }
5455 
5456  template<typename T>
5457  inline T median(T val0, T val1, T val2, T val3, T val4, T val5, T val6) {
5458  T tmp = std::min(val0,val5);
5459  val5 = std::max(val0,val5); val0 = tmp; tmp = std::min(val0,val3); val3 = std::max(val0,val3); val0 = tmp;
5460  tmp = std::min(val1,val6); val6 = std::max(val1,val6); val1 = tmp; tmp = std::min(val2,val4);
5461  val4 = std::max(val2,val4); val2 = tmp; val1 = std::max(val0,val1); tmp = std::min(val3,val5);
5462  val5 = std::max(val3,val5); val3 = tmp; tmp = std::min(val2,val6); val6 = std::max(val2,val6);
5463  val3 = std::max(tmp,val3); val3 = std::min(val3,val6); tmp = std::min(val4,val5); val4 = std::max(val1,tmp);
5464  tmp = std::min(val1,tmp); val3 = std::max(tmp,val3);
5465  return std::min(val3,val4);
5466  }
5467 
5468  template<typename T>
5469  inline T median(T val0, T val1, T val2, T val3, T val4, T val5, T val6, T val7, T val8) {
5470  T tmp = std::min(val1,val2);
5471  val2 = std::max(val1,val2); val1 = tmp; tmp = std::min(val4,val5);
5472  val5 = std::max(val4,val5); val4 = tmp; tmp = std::min(val7,val8);
5473  val8 = std::max(val7,val8); val7 = tmp; tmp = std::min(val0,val1);
5474  val1 = std::max(val0,val1); val0 = tmp; tmp = std::min(val3,val4);
5475  val4 = std::max(val3,val4); val3 = tmp; tmp = std::min(val6,val7);
5476  val7 = std::max(val6,val7); val6 = tmp; tmp = std::min(val1,val2);
5477  val2 = std::max(val1,val2); val1 = tmp; tmp = std::min(val4,val5);
5478  val5 = std::max(val4,val5); val4 = tmp; tmp = std::min(val7,val8);
5479  val8 = std::max(val7,val8); val3 = std::max(val0,val3); val5 = std::min(val5,val8);
5480  val7 = std::max(val4,tmp); tmp = std::min(val4,tmp); val6 = std::max(val3,val6);
5481  val4 = std::max(val1,tmp); val2 = std::min(val2,val5); val4 = std::min(val4,val7);
5482  tmp = std::min(val4,val2); val2 = std::max(val4,val2); val4 = std::max(val6,tmp);
5483  return std::min(val4,val2);
5484  }
5485 
5486  template<typename T>
5487  inline T median(T val0, T val1, T val2, T val3, T val4, T val5, T val6, T val7, T val8, T val9, T val10, T val11,
5488  T val12) {
5489  T tmp = std::min(val1,val7);
5490  val7 = std::max(val1,val7); val1 = tmp; tmp = std::min(val9,val11); val11 = std::max(val9,val11); val9 = tmp;
5491  tmp = std::min(val3,val4); val4 = std::max(val3,val4); val3 = tmp; tmp = std::min(val5,val8);
5492  val8 = std::max(val5,val8); val5 = tmp; tmp = std::min(val0,val12); val12 = std::max(val0,val12);
5493  val0 = tmp; tmp = std::min(val2,val6); val6 = std::max(val2,val6); val2 = tmp; tmp = std::min(val0,val1);
5494  val1 = std::max(val0,val1); val0 = tmp; tmp = std::min(val2,val3); val3 = std::max(val2,val3); val2 = tmp;
5495  tmp = std::min(val4,val6); val6 = std::max(val4,val6); val4 = tmp; tmp = std::min(val8,val11);
5496  val11 = std::max(val8,val11); val8 = tmp; tmp = std::min(val7,val12); val12 = std::max(val7,val12); val7 = tmp;
5497  tmp = std::min(val5,val9); val9 = std::max(val5,val9); val5 = tmp; tmp = std::min(val0,val2);
5498  val2 = std::max(val0,val2); val0 = tmp; tmp = std::min(val3,val7); val7 = std::max(val3,val7); val3 = tmp;
5499  tmp = std::min(val10,val11); val11 = std::max(val10,val11); val10 = tmp; tmp = std::min(val1,val4);
5500  val4 = std::max(val1,val4); val1 = tmp; tmp = std::min(val6,val12); val12 = std::max(val6,val12); val6 = tmp;
5501  tmp = std::min(val7,val8); val8 = std::max(val7,val8); val7 = tmp; val11 = std::min(val11,val12);
5502  tmp = std::min(val4,val9); val9 = std::max(val4,val9); val4 = tmp; tmp = std::min(val6,val10);
5503  val10 = std::max(val6,val10); val6 = tmp; tmp = std::min(val3,val4); val4 = std::max(val3,val4); val3 = tmp;
5504  tmp = std::min(val5,val6); val6 = std::max(val5,val6); val5 = tmp; val8 = std::min(val8,val9);
5505  val10 = std::min(val10,val11); tmp = std::min(val1,val7); val7 = std::max(val1,val7); val1 = tmp;
5506  tmp = std::min(val2,val6); val6 = std::max(val2,val6); val2 = tmp; val3 = std::max(val1,val3);
5507  tmp = std::min(val4,val7); val7 = std::max(val4,val7); val4 = tmp; val8 = std::min(val8,val10);
5508  val5 = std::max(val0,val5); val5 = std::max(val2,val5); tmp = std::min(val6,val8); val8 = std::max(val6,val8);
5509  val5 = std::max(val3,val5); val7 = std::min(val7,val8); val6 = std::max(val4,tmp); tmp = std::min(val4,tmp);
5510  val5 = std::max(tmp,val5); val6 = std::min(val6,val7);
5511  return std::max(val5,val6);
5512  }
5513 
5514  template<typename T>
5515  inline T median(T val0, T val1, T val2, T val3, T val4,
5516  T val5, T val6, T val7, T val8, T val9,
5517  T val10, T val11, T val12, T val13, T val14,
5518  T val15, T val16, T val17, T val18, T val19,
5519  T val20, T val21, T val22, T val23, T val24) {
5520  T tmp = std::min(val0,val1);
5521  val1 = std::max(val0,val1); val0 = tmp; tmp = std::min(val3,val4); val4 = std::max(val3,val4);
5522  val3 = tmp; tmp = std::min(val2,val4); val4 = std::max(val2,val4); val2 = std::min(tmp,val3);
5523  val3 = std::max(tmp,val3); tmp = std::min(val6,val7); val7 = std::max(val6,val7); val6 = tmp;
5524  tmp = std::min(val5,val7); val7 = std::max(val5,val7); val5 = std::min(tmp,val6); val6 = std::max(tmp,val6);
5525  tmp = std::min(val9,val10); val10 = std::max(val9,val10); val9 = tmp; tmp = std::min(val8,val10);
5526  val10 = std::max(val8,val10); val8 = std::min(tmp,val9); val9 = std::max(tmp,val9);
5527  tmp = std::min(val12,val13); val13 = std::max(val12,val13); val12 = tmp; tmp = std::min(val11,val13);
5528  val13 = std::max(val11,val13); val11 = std::min(tmp,val12); val12 = std::max(tmp,val12);
5529  tmp = std::min(val15,val16); val16 = std::max(val15,val16); val15 = tmp; tmp = std::min(val14,val16);
5530  val16 = std::max(val14,val16); val14 = std::min(tmp,val15); val15 = std::max(tmp,val15);
5531  tmp = std::min(val18,val19); val19 = std::max(val18,val19); val18 = tmp; tmp = std::min(val17,val19);
5532  val19 = std::max(val17,val19); val17 = std::min(tmp,val18); val18 = std::max(tmp,val18);
5533  tmp = std::min(val21,val22); val22 = std::max(val21,val22); val21 = tmp; tmp = std::min(val20,val22);
5534  val22 = std::max(val20,val22); val20 = std::min(tmp,val21); val21 = std::max(tmp,val21);
5535  tmp = std::min(val23,val24); val24 = std::max(val23,val24); val23 = tmp; tmp = std::min(val2,val5);
5536  val5 = std::max(val2,val5); val2 = tmp; tmp = std::min(val3,val6); val6 = std::max(val3,val6); val3 = tmp;
5537  tmp = std::min(val0,val6); val6 = std::max(val0,val6); val0 = std::min(tmp,val3); val3 = std::max(tmp,val3);
5538  tmp = std::min(val4,val7); val7 = std::max(val4,val7); val4 = tmp; tmp = std::min(val1,val7);
5539  val7 = std::max(val1,val7); val1 = std::min(tmp,val4); val4 = std::max(tmp,val4); tmp = std::min(val11,val14);
5540  val14 = std::max(val11,val14); val11 = tmp; tmp = std::min(val8,val14); val14 = std::max(val8,val14);
5541  val8 = std::min(tmp,val11); val11 = std::max(tmp,val11); tmp = std::min(val12,val15);
5542  val15 = std::max(val12,val15); val12 = tmp; tmp = std::min(val9,val15); val15 = std::max(val9,val15);
5543  val9 = std::min(tmp,val12); val12 = std::max(tmp,val12); tmp = std::min(val13,val16);
5544  val16 = std::max(val13,val16); val13 = tmp; tmp = std::min(val10,val16); val16 = std::max(val10,val16);
5545  val10 = std::min(tmp,val13); val13 = std::max(tmp,val13); tmp = std::min(val20,val23);
5546  val23 = std::max(val20,val23); val20 = tmp; tmp = std::min(val17,val23); val23 = std::max(val17,val23);
5547  val17 = std::min(tmp,val20); val20 = std::max(tmp,val20); tmp = std::min(val21,val24);
5548  val24 = std::max(val21,val24); val21 = tmp; tmp = std::min(val18,val24); val24 = std::max(val18,val24);
5549  val18 = std::min(tmp,val21); val21 = std::max(tmp,val21); tmp = std::min(val19,val22);
5550  val22 = std::max(val19,val22); val19 = tmp; val17 = std::max(val8,val17); tmp = std::min(val9,val18);
5551  val18 = std::max(val9,val18); val9 = tmp; tmp = std::min(val0,val18); val18 = std::max(val0,val18);
5552  val9 = std::max(tmp,val9); tmp = std::min(val10,val19); val19 = std::max(val10,val19); val10 = tmp;
5553  tmp = std::min(val1,val19); val19 = std::max(val1,val19); val1 = std::min(tmp,val10);
5554  val10 = std::max(tmp,val10); tmp = std::min(val11,val20); val20 = std::max(val11,val20); val11 = tmp;
5555  tmp = std::min(val2,val20); val20 = std::max(val2,val20); val11 = std::max(tmp,val11);
5556  tmp = std::min(val12,val21); val21 = std::max(val12,val21); val12 = tmp; tmp = std::min(val3,val21);
5557  val21 = std::max(val3,val21); val3 = std::min(tmp,val12); val12 = std::max(tmp,val12);
5558  tmp = std::min(val13,val22); val22 = std::max(val13,val22); val4 = std::min(val4,val22);
5559  val13 = std::max(val4,tmp); tmp = std::min(val4,tmp); val4 = tmp; tmp = std::min(val14,val23);
5560  val23 = std::max(val14,val23); val14 = tmp; tmp = std::min(val5,val23); val23 = std::max(val5,val23);
5561  val5 = std::min(tmp,val14); val14 = std::max(tmp,val14); tmp = std::min(val15,val24);
5562  val24 = std::max(val15,val24); val15 = tmp; val6 = std::min(val6,val24); tmp = std::min(val6,val15);
5563  val15 = std::max(val6,val15); val6 = tmp; tmp = std::min(val7,val16); val7 = std::min(tmp,val19);
5564  tmp = std::min(val13,val21); val15 = std::min(val15,val23); tmp = std::min(val7,tmp);
5565  val7 = std::min(tmp,val15); val9 = std::max(val1,val9); val11 = std::max(val3,val11);
5566  val17 = std::max(val5,val17); val17 = std::max(val11,val17); val17 = std::max(val9,val17);
5567  tmp = std::min(val4,val10); val10 = std::max(val4,val10); val4 = tmp; tmp = std::min(val6,val12);
5568  val12 = std::max(val6,val12); val6 = tmp; tmp = std::min(val7,val14); val14 = std::max(val7,val14);
5569  val7 = tmp; tmp = std::min(val4,val6); val6 = std::max(val4,val6); val7 = std::max(tmp,val7);
5570  tmp = std::min(val12,val14); val14 = std::max(val12,val14); val12 = tmp; val10 = std::min(val10,val14);
5571  tmp = std::min(val6,val7); val7 = std::max(val6,val7); val6 = tmp; tmp = std::min(val10,val12);
5572  val12 = std::max(val10,val12); val10 = std::max(val6,tmp); tmp = std::min(val6,tmp);
5573  val17 = std::max(tmp,val17); tmp = std::min(val12,val17); val17 = std::max(val12,val17); val12 = tmp;
5574  val7 = std::min(val7,val17); tmp = std::min(val7,val10); val10 = std::max(val7,val10); val7 = tmp;
5575  tmp = std::min(val12,val18); val18 = std::max(val12,val18); val12 = std::max(val7,tmp);
5576  val10 = std::min(val10,val18); tmp = std::min(val12,val20); val20 = std::max(val12,val20); val12 = tmp;
5577  tmp = std::min(val10,val20);
5578  return std::max(tmp,val12);
5579  }
5580 
5581  template<typename T>
5582  inline T median(T val0, T val1, T val2, T val3, T val4, T val5, T val6,
5583  T val7, T val8, T val9, T val10, T val11, T val12, T val13,
5584  T val14, T val15, T val16, T val17, T val18, T val19, T val20,
5585  T val21, T val22, T val23, T val24, T val25, T val26, T val27,
5586  T val28, T val29, T val30, T val31, T val32, T val33, T val34,
5587  T val35, T val36, T val37, T val38, T val39, T val40, T val41,
5588  T val42, T val43, T val44, T val45, T val46, T val47, T val48) {
5589  T tmp = std::min(val0,val32);
5590  val32 = std::max(val0,val32); val0 = tmp; tmp = std::min(val1,val33); val33 = std::max(val1,val33); val1 = tmp;
5591  tmp = std::min(val2,val34); val34 = std::max(val2,val34); val2 = tmp; tmp = std::min(val3,val35);
5592  val35 = std::max(val3,val35); val3 = tmp; tmp = std::min(val4,val36); val36 = std::max(val4,val36); val4 = tmp;
5593  tmp = std::min(val5,val37); val37 = std::max(val5,val37); val5 = tmp; tmp = std::min(val6,val38);
5594  val38 = std::max(val6,val38); val6 = tmp; tmp = std::min(val7,val39); val39 = std::max(val7,val39); val7 = tmp;
5595  tmp = std::min(val8,val40); val40 = std::max(val8,val40); val8 = tmp; tmp = std::min(val9,val41);
5596  val41 = std::max(val9,val41); val9 = tmp; tmp = std::min(val10,val42); val42 = std::max(val10,val42);
5597  val10 = tmp; tmp = std::min(val11,val43); val43 = std::max(val11,val43); val11 = tmp;
5598  tmp = std::min(val12,val44); val44 = std::max(val12,val44); val12 = tmp; tmp = std::min(val13,val45);
5599  val45 = std::max(val13,val45); val13 = tmp; tmp = std::min(val14,val46); val46 = std::max(val14,val46);
5600  val14 = tmp; tmp = std::min(val15,val47); val47 = std::max(val15,val47); val15 = tmp;
5601  tmp = std::min(val16,val48); val48 = std::max(val16,val48); val16 = tmp; tmp = std::min(val0,val16);
5602  val16 = std::max(val0,val16); val0 = tmp; tmp = std::min(val1,val17); val17 = std::max(val1,val17);
5603  val1 = tmp; tmp = std::min(val2,val18); val18 = std::max(val2,val18); val2 = tmp; tmp = std::min(val3,val19);
5604  val19 = std::max(val3,val19); val3 = tmp; tmp = std::min(val4,val20); val20 = std::max(val4,val20); val4 = tmp;
5605  tmp = std::min(val5,val21); val21 = std::max(val5,val21); val5 = tmp; tmp = std::min(val6,val22);
5606  val22 = std::max(val6,val22); val6 = tmp; tmp = std::min(val7,val23); val23 = std::max(val7,val23); val7 = tmp;
5607  tmp = std::min(val8,val24); val24 = std::max(val8,val24); val8 = tmp; tmp = std::min(val9,val25);
5608  val25 = std::max(val9,val25); val9 = tmp; tmp = std::min(val10,val26); val26 = std::max(val10,val26);
5609  val10 = tmp; tmp = std::min(val11,val27); val27 = std::max(val11,val27); val11 = tmp;
5610  tmp = std::min(val12,val28); val28 = std::max(val12,val28); val12 = tmp; tmp = std::min(val13,val29);
5611  val29 = std::max(val13,val29); val13 = tmp; tmp = std::min(val14,val30); val30 = std::max(val14,val30);
5612  val14 = tmp; tmp = std::min(val15,val31); val31 = std::max(val15,val31); val15 = tmp;
5613  tmp = std::min(val32,val48); val48 = std::max(val32,val48); val32 = tmp; tmp = std::min(val16,val32);
5614  val32 = std::max(val16,val32); val16 = tmp; tmp = std::min(val17,val33); val33 = std::max(val17,val33);
5615  val17 = tmp; tmp = std::min(val18,val34); val34 = std::max(val18,val34); val18 = tmp;
5616  tmp = std::min(val19,val35); val35 = std::max(val19,val35); val19 = tmp; tmp = std::min(val20,val36);
5617  val36 = std::max(val20,val36); val20 = tmp; tmp = std::min(val21,val37); val37 = std::max(val21,val37);
5618  val21 = tmp; tmp = std::min(val22,val38); val38 = std::max(val22,val38); val22 = tmp;
5619  tmp = std::min(val23,val39); val39 = std::max(val23,val39); val23 = tmp; tmp = std::min(val24,val40);
5620  val40 = std::max(val24,val40); val24 = tmp; tmp = std::min(val25,val41); val41 = std::max(val25,val41);
5621  val25 = tmp; tmp = std::min(val26,val42); val42 = std::max(val26,val42); val26 = tmp;
5622  tmp = std::min(val27,val43); val43 = std::max(val27,val43); val27 = tmp; tmp = std::min(val28,val44);
5623  val44 = std::max(val28,val44); val28 = tmp; tmp = std::min(val29,val45); val45 = std::max(val29,val45);
5624  val29 = tmp; tmp = std::min(val30,val46); val46 = std::max(val30,val46); val30 = tmp;
5625  tmp = std::min(val31,val47); val47 = std::max(val31,val47); val31 = tmp; tmp = std::min(val0,val8);
5626  val8 = std::max(val0,val8); val0 = tmp; tmp = std::min(val1,val9); val9 = std::max(val1,val9); val1 = tmp;
5627  tmp = std::min(val2,val10); val10 = std::max(val2,val10); val2 = tmp; tmp = std::min(val3,val11);
5628  val11 = std::max(val3,val11); val3 = tmp; tmp = std::min(val4,val12); val12 = std::max(val4,val12); val4 = tmp;
5629  tmp = std::min(val5,val13); val13 = std::max(val5,val13); val5 = tmp; tmp = std::min(val6,val14);
5630  val14 = std::max(val6,val14); val6 = tmp; tmp = std::min(val7,val15); val15 = std::max(val7,val15); val7 = tmp;
5631  tmp = std::min(val16,val24); val24 = std::max(val16,val24); val16 = tmp; tmp = std::min(val17,val25);
5632  val25 = std::max(val17,val25); val17 = tmp; tmp = std::min(val18,val26); val26 = std::max(val18,val26);
5633  val18 = tmp; tmp = std::min(val19,val27); val27 = std::max(val19,val27); val19 = tmp;
5634  tmp = std::min(val20,val28); val28 = std::max(val20,val28); val20 = tmp; tmp = std::min(val21,val29);
5635  val29 = std::max(val21,val29); val21 = tmp; tmp = std::min(val22,val30); val30 = std::max(val22,val30);
5636  val22 = tmp; tmp = std::min(val23,val31); val31 = std::max(val23,val31); val23 = tmp;
5637  tmp = std::min(val32,val40); val40 = std::max(val32,val40); val32 = tmp; tmp = std::min(val33,val41);
5638  val41 = std::max(val33,val41); val33 = tmp; tmp = std::min(val34,val42); val42 = std::max(val34,val42);
5639  val34 = tmp; tmp = std::min(val35,val43); val43 = std::max(val35,val43); val35 = tmp;
5640  tmp = std::min(val36,val44); val44 = std::max(val36,val44); val36 = tmp; tmp = std::min(val37,val45);
5641  val45 = std::max(val37,val45); val37 = tmp; tmp = std::min(val38,val46); val46 = std::max(val38,val46);
5642  val38 = tmp; tmp = std::min(val39,val47); val47 = std::max(val39,val47); val39 = tmp;
5643  tmp = std::min(val8,val32); val32 = std::max(val8,val32); val8 = tmp; tmp = std::min(val9,val33);
5644  val33 = std::max(val9,val33); val9 = tmp; tmp = std::min(val10,val34); val34 = std::max(val10,val34);
5645  val10 = tmp; tmp = std::min(val11,val35); val35 = std::max(val11,val35); val11 = tmp;
5646  tmp = std::min(val12,val36); val36 = std::max(val12,val36); val12 = tmp; tmp = std::min(val13,val37);
5647  val37 = std::max(val13,val37); val13 = tmp; tmp = std::min(val14,val38); val38 = std::max(val14,val38);
5648  val14 = tmp; tmp = std::min(val15,val39); val39 = std::max(val15,val39); val15 = tmp;
5649  tmp = std::min(val24,val48); val48 = std::max(val24,val48); val24 = tmp; tmp = std::min(val8,val16);
5650  val16 = std::max(val8,val16); val8 = tmp; tmp = std::min(val9,val17); val17 = std::max(val9,val17);
5651  val9 = tmp; tmp = std::min(val10,val18); val18 = std::max(val10,val18); val10 = tmp;
5652  tmp = std::min(val11,val19); val19 = std::max(val11,val19); val11 = tmp; tmp = std::min(val12,val20);
5653  val20 = std::max(val12,val20); val12 = tmp; tmp = std::min(val13,val21); val21 = std::max(val13,val21);
5654  val13 = tmp; tmp = std::min(val14,val22); val22 = std::max(val14,val22); val14 = tmp;
5655  tmp = std::min(val15,val23); val23 = std::max(val15,val23); val15 = tmp; tmp = std::min(val24,val32);
5656  val32 = std::max(val24,val32); val24 = tmp; tmp = std::min(val25,val33); val33 = std::max(val25,val33);
5657  val25 = tmp; tmp = std::min(val26,val34); val34 = std::max(val26,val34); val26 = tmp;
5658  tmp = std::min(val27,val35); val35 = std::max(val27,val35); val27 = tmp; tmp = std::min(val28,val36);
5659  val36 = std::max(val28,val36); val28 = tmp; tmp = std::min(val29,val37); val37 = std::max(val29,val37);
5660  val29 = tmp; tmp = std::min(val30,val38); val38 = std::max(val30,val38); val30 = tmp;
5661  tmp = std::min(val31,val39); val39 = std::max(val31,val39); val31 = tmp; tmp = std::min(val40,val48);
5662  val48 = std::max(val40,val48); val40 = tmp; tmp = std::min(val0,val4); val4 = std::max(val0,val4);
5663  val0 = tmp; tmp = std::min(val1,val5); val5 = std::max(val1,val5); val1 = tmp; tmp = std::min(val2,val6);
5664  val6 = std::max(val2,val6); val2 = tmp; tmp = std::min(val3,val7); val7 = std::max(val3,val7); val3 = tmp;
5665  tmp = std::min(val8,val12); val12 = std::max(val8,val12); val8 = tmp; tmp = std::min(val9,val13);
5666  val13 = std::max(val9,val13); val9 = tmp; tmp = std::min(val10,val14); val14 = std::max(val10,val14);
5667  val10 = tmp; tmp = std::min(val11,val15); val15 = std::max(val11,val15); val11 = tmp;
5668  tmp = std::min(val16,val20); val20 = std::max(val16,val20); val16 = tmp; tmp = std::min(val17,val21);
5669  val21 = std::max(val17,val21); val17 = tmp; tmp = std::min(val18,val22); val22 = std::max(val18,val22);
5670  val18 = tmp; tmp = std::min(val19,val23); val23 = std::max(val19,val23); val19 = tmp;
5671  tmp = std::min(val24,val28); val28 = std::max(val24,val28); val24 = tmp; tmp = std::min(val25,val29);
5672  val29 = std::max(val25,val29); val25 = tmp; tmp = std::min(val26,val30); val30 = std::max(val26,val30);
5673  val26 = tmp; tmp = std::min(val27,val31); val31 = std::max(val27,val31); val27 = tmp;
5674  tmp = std::min(val32,val36); val36 = std::max(val32,val36); val32 = tmp; tmp = std::min(val33,val37);
5675  val37 = std::max(val33,val37); val33 = tmp; tmp = std::min(val34,val38); val38 = std::max(val34,val38);
5676  val34 = tmp; tmp = std::min(val35,val39); val39 = std::max(val35,val39); val35 = tmp;
5677  tmp = std::min(val40,val44); val44 = std::max(val40,val44); val40 = tmp; tmp = std::min(val41,val45);
5678  val45 = std::max(val41,val45); val41 = tmp; tmp = std::min(val42,val46); val46 = std::max(val42,val46);
5679  val42 = tmp; tmp = std::min(val43,val47); val47 = std::max(val43,val47); val43 = tmp;
5680  tmp = std::min(val4,val32); val32 = std::max(val4,val32); val4 = tmp; tmp = std::min(val5,val33);
5681  val33 = std::max(val5,val33); val5 = tmp; tmp = std::min(val6,val34); val34 = std::max(val6,val34);
5682  val6 = tmp; tmp = std::min(val7,val35); val35 = std::max(val7,val35); val7 = tmp;
5683  tmp = std::min(val12,val40); val40 = std::max(val12,val40); val12 = tmp; tmp = std::min(val13,val41);
5684  val41 = std::max(val13,val41); val13 = tmp; tmp = std::min(val14,val42); val42 = std::max(val14,val42);
5685  val14 = tmp; tmp = std::min(val15,val43); val43 = std::max(val15,val43); val15 = tmp;
5686  tmp = std::min(val20,val48); val48 = std::max(val20,val48); val20 = tmp; tmp = std::min(val4,val16);
5687  val16 = std::max(val4,val16); val4 = tmp; tmp = std::min(val5,val17); val17 = std::max(val5,val17);
5688  val5 = tmp; tmp = std::min(val6,val18); val18 = std::max(val6,val18); val6 = tmp;
5689  tmp = std::min(val7,val19); val19 = std::max(val7,val19); val7 = tmp; tmp = std::min(val12,val24);
5690  val24 = std::max(val12,val24); val12 = tmp; tmp = std::min(val13,val25); val25 = std::max(val13,val25);
5691  val13 = tmp; tmp = std::min(val14,val26); val26 = std::max(val14,val26); val14 = tmp;
5692  tmp = std::min(val15,val27); val27 = std::max(val15,val27); val15 = tmp; tmp = std::min(val20,val32);
5693  val32 = std::max(val20,val32); val20 = tmp; tmp = std::min(val21,val33); val33 = std::max(val21,val33);
5694  val21 = tmp; tmp = std::min(val22,val34); val34 = std::max(val22,val34); val22 = tmp;
5695  tmp = std::min(val23,val35); val35 = std::max(val23,val35); val23 = tmp; tmp = std::min(val28,val40);
5696  val40 = std::max(val28,val40); val28 = tmp; tmp = std::min(val29,val41); val41 = std::max(val29,val41);
5697  val29 = tmp; tmp = std::min(val30,val42); val42 = std::max(val30,val42); val30 = tmp;
5698  tmp = std::min(val31,val43); val43 = std::max(val31,val43); val31 = tmp; tmp = std::min(val36,val48);
5699  val48 = std::max(val36,val48); val36 = tmp; tmp = std::min(val4,val8); val8 = std::max(val4,val8);
5700  val4 = tmp; tmp = std::min(val5,val9); val9 = std::max(val5,val9); val5 = tmp; tmp = std::min(val6,val10);
5701  val10 = std::max(val6,val10); val6 = tmp; tmp = std::min(val7,val11); val11 = std::max(val7,val11); val7 = tmp;
5702  tmp = std::min(val12,val16); val16 = std::max(val12,val16); val12 = tmp; tmp = std::min(val13,val17);
5703  val17 = std::max(val13,val17); val13 = tmp; tmp = std::min(val14,val18); val18 = std::max(val14,val18);
5704  val14 = tmp; tmp = std::min(val15,val19); val19 = std::max(val15,val19); val15 = tmp;
5705  tmp = std::min(val20,val24); val24 = std::max(val20,val24); val20 = tmp; tmp = std::min(val21,val25);
5706  val25 = std::max(val21,val25); val21 = tmp; tmp = std::min(val22,val26); val26 = std::max(val22,val26);
5707  val22 = tmp; tmp = std::min(val23,val27); val27 = std::max(val23,val27); val23 = tmp;
5708  tmp = std::min(val28,val32); val32 = std::max(val28,val32); val28 = tmp; tmp = std::min(val29,val33);
5709  val33 = std::max(val29,val33); val29 = tmp; tmp = std::min(val30,val34); val34 = std::max(val30,val34);
5710  val30 = tmp; tmp = std::min(val31,val35); val35 = std::max(val31,val35); val31 = tmp;
5711  tmp = std::min(val36,val40); val40 = std::max(val36,val40); val36 = tmp; tmp = std::min(val37,val41);
5712  val41 = std::max(val37,val41); val37 = tmp; tmp = std::min(val38,val42); val42 = std::max(val38,val42);
5713  val38 = tmp; tmp = std::min(val39,val43); val43 = std::max(val39,val43); val39 = tmp;
5714  tmp = std::min(val44,val48); val48 = std::max(val44,val48); val44 = tmp; tmp = std::min(val0,val2);
5715  val2 = std::max(val0,val2); val0 = tmp; tmp = std::min(val1,val3); val3 = std::max(val1,val3); val1 = tmp;
5716  tmp = std::min(val4,val6); val6 = std::max(val4,val6); val4 = tmp; tmp = std::min(val5,val7);
5717  val7 = std::max(val5,val7); val5 = tmp; tmp = std::min(val8,val10); val10 = std::max(val8,val10); val8 = tmp;
5718  tmp = std::min(val9,val11); val11 = std::max(val9,val11); val9 = tmp; tmp = std::min(val12,val14);
5719  val14 = std::max(val12,val14); val12 = tmp; tmp = std::min(val13,val15); val15 = std::max(val13,val15);
5720  val13 = tmp; tmp = std::min(val16,val18); val18 = std::max(val16,val18); val16 = tmp;
5721  tmp = std::min(val17,val19); val19 = std::max(val17,val19); val17 = tmp; tmp = std::min(val20,val22);
5722  val22 = std::max(val20,val22); val20 = tmp; tmp = std::min(val21,val23); val23 = std::max(val21,val23);
5723  val21 = tmp; tmp = std::min(val24,val26); val26 = std::max(val24,val26); val24 = tmp;
5724  tmp = std::min(val25,val27); val27 = std::max(val25,val27); val25 = tmp; tmp = std::min(val28,val30);
5725  val30 = std::max(val28,val30); val28 = tmp; tmp = std::min(val29,val31); val31 = std::max(val29,val31);
5726  val29 = tmp; tmp = std::min(val32,val34); val34 = std::max(val32,val34); val32 = tmp;
5727  tmp = std::min(val33,val35); val35 = std::max(val33,val35); val33 = tmp; tmp = std::min(val36,val38);
5728  val38 = std::max(val36,val38); val36 = tmp; tmp = std::min(val37,val39); val39 = std::max(val37,val39);
5729  val37 = tmp; tmp = std::min(val40,val42); val42 = std::max(val40,val42); val40 = tmp;
5730  tmp = std::min(val41,val43); val43 = std::max(val41,val43); val41 = tmp; tmp = std::min(val44,val46);
5731  val46 = std::max(val44,val46); val44 = tmp; tmp = std::min(val45,val47); val47 = std::max(val45,val47);
5732  val45 = tmp; tmp = std::min(val2,val32); val32 = std::max(val2,val32); val2 = tmp; tmp = std::min(val3,val33);
5733  val33 = std::max(val3,val33); val3 = tmp; tmp = std::min(val6,val36); val36 = std::max(val6,val36); val6 = tmp;
5734  tmp = std::min(val7,val37); val37 = std::max(val7,val37); val7 = tmp; tmp = std::min(val10,val40);
5735  val40 = std::max(val10,val40); val10 = tmp; tmp = std::min(val11,val41); val41 = std::max(val11,val41);
5736  val11 = tmp; tmp = std::min(val14,val44); val44 = std::max(val14,val44); val14 = tmp;
5737  tmp = std::min(val15,val45); val45 = std::max(val15,val45); val15 = tmp; tmp = std::min(val18,val48);
5738  val48 = std::max(val18,val48); val18 = tmp; tmp = std::min(val2,val16); val16 = std::max(val2,val16);
5739  val2 = tmp; tmp = std::min(val3,val17); val17 = std::max(val3,val17); val3 = tmp;
5740  tmp = std::min(val6,val20); val20 = std::max(val6,val20); val6 = tmp; tmp = std::min(val7,val21);
5741  val21 = std::max(val7,val21); val7 = tmp; tmp = std::min(val10,val24); val24 = std::max(val10,val24);
5742  val10 = tmp; tmp = std::min(val11,val25); val25 = std::max(val11,val25); val11 = tmp;
5743  tmp = std::min(val14,val28); val28 = std::max(val14,val28); val14 = tmp; tmp = std::min(val15,val29);
5744  val29 = std::max(val15,val29); val15 = tmp; tmp = std::min(val18,val32); val32 = std::max(val18,val32);
5745  val18 = tmp; tmp = std::min(val19,val33); val33 = std::max(val19,val33); val19 = tmp;
5746  tmp = std::min(val22,val36); val36 = std::max(val22,val36); val22 = tmp; tmp = std::min(val23,val37);
5747  val37 = std::max(val23,val37); val23 = tmp; tmp = std::min(val26,val40); val40 = std::max(val26,val40);
5748  val26 = tmp; tmp = std::min(val27,val41); val41 = std::max(val27,val41); val27 = tmp;
5749  tmp = std::min(val30,val44); val44 = std::max(val30,val44); val30 = tmp; tmp = std::min(val31,val45);
5750  val45 = std::max(val31,val45); val31 = tmp; tmp = std::min(val34,val48); val48 = std::max(val34,val48);
5751  val34 = tmp; tmp = std::min(val2,val8); val8 = std::max(val2,val8); val2 = tmp; tmp = std::min(val3,val9);
5752  val9 = std::max(val3,val9); val3 = tmp; tmp = std::min(val6,val12); val12 = std::max(val6,val12); val6 = tmp;
5753  tmp = std::min(val7,val13); val13 = std::max(val7,val13); val7 = tmp; tmp = std::min(val10,val16);
5754  val16 = std::max(val10,val16); val10 = tmp; tmp = std::min(val11,val17); val17 = std::max(val11,val17);
5755  val11 = tmp; tmp = std::min(val14,val20); val20 = std::max(val14,val20); val14 = tmp;
5756  tmp = std::min(val15,val21); val21 = std::max(val15,val21); val15 = tmp; tmp = std::min(val18,val24);
5757  val24 = std::max(val18,val24); val18 = tmp; tmp = std::min(val19,val25); val25 = std::max(val19,val25);
5758  val19 = tmp; tmp = std::min(val22,val28); val28 = std::max(val22,val28); val22 = tmp;
5759  tmp = std::min(val23,val29); val29 = std::max(val23,val29); val23 = tmp; tmp = std::min(val26,val32);
5760  val32 = std::max(val26,val32); val26 = tmp; tmp = std::min(val27,val33); val33 = std::max(val27,val33);
5761  val27 = tmp; tmp = std::min(val30,val36); val36 = std::max(val30,val36); val30 = tmp;
5762  tmp = std::min(val31,val37); val37 = std::max(val31,val37); val31 = tmp; tmp = std::min(val34,val40);
5763  val40 = std::max(val34,val40); val34 = tmp; tmp = std::min(val35,val41); val41 = std::max(val35,val41);
5764  val35 = tmp; tmp = std::min(val38,val44); val44 = std::max(val38,val44); val38 = tmp;
5765  tmp = std::min(val39,val45); val45 = std::max(val39,val45); val39 = tmp; tmp = std::min(val42,val48);
5766  val48 = std::max(val42,val48); val42 = tmp; tmp = std::min(val2,val4); val4 = std::max(val2,val4);
5767  val2 = tmp; tmp = std::min(val3,val5); val5 = std::max(val3,val5); val3 = tmp; tmp = std::min(val6,val8);
5768  val8 = std::max(val6,val8); val6 = tmp; tmp = std::min(val7,val9); val9 = std::max(val7,val9); val7 = tmp;
5769  tmp = std::min(val10,val12); val12 = std::max(val10,val12); val10 = tmp; tmp = std::min(val11,val13);
5770  val13 = std::max(val11,val13); val11 = tmp; tmp = std::min(val14,val16); val16 = std::max(val14,val16);
5771  val14 = tmp; tmp = std::min(val15,val17); val17 = std::max(val15,val17); val15 = tmp;
5772  tmp = std::min(val18,val20); val20 = std::max(val18,val20); val18 = tmp; tmp = std::min(val19,val21);
5773  val21 = std::max(val19,val21); val19 = tmp; tmp = std::min(val22,val24); val24 = std::max(val22,val24);
5774  val22 = tmp; tmp = std::min(val23,val25); val25 = std::max(val23,val25); val23 = tmp;
5775  tmp = std::min(val26,val28); val28 = std::max(val26,val28); val26 = tmp; tmp = std::min(val27,val29);
5776  val29 = std::max(val27,val29); val27 = tmp; tmp = std::min(val30,val32); val32 = std::max(val30,val32);
5777  val30 = tmp; tmp = std::min(val31,val33); val33 = std::max(val31,val33); val31 = tmp;
5778  tmp = std::min(val34,val36); val36 = std::max(val34,val36); val34 = tmp; tmp = std::min(val35,val37);
5779  val37 = std::max(val35,val37); val35 = tmp; tmp = std::min(val38,val40); val40 = std::max(val38,val40);
5780  val38 = tmp; tmp = std::min(val39,val41); val41 = std::max(val39,val41); val39 = tmp;
5781  tmp = std::min(val42,val44); val44 = std::max(val42,val44); val42 = tmp; tmp = std::min(val43,val45);
5782  val45 = std::max(val43,val45); val43 = tmp; tmp = std::min(val46,val48); val48 = std::max(val46,val48);
5783  val46 = tmp; val1 = std::max(val0,val1); val3 = std::max(val2,val3); val5 = std::max(val4,val5);
5784  val7 = std::max(val6,val7); val9 = std::max(val8,val9); val11 = std::max(val10,val11);
5785  val13 = std::max(val12,val13); val15 = std::max(val14,val15); val17 = std::max(val16,val17);
5786  val19 = std::max(val18,val19); val21 = std::max(val20,val21); val23 = std::max(val22,val23);
5787  val24 = std::min(val24,val25); val26 = std::min(val26,val27); val28 = std::min(val28,val29);
5788  val30 = std::min(val30,val31); val32 = std::min(val32,val33); val34 = std::min(val34,val35);
5789  val36 = std::min(val36,val37); val38 = std::min(val38,val39); val40 = std::min(val40,val41);
5790  val42 = std::min(val42,val43); val44 = std::min(val44,val45); val46 = std::min(val46,val47);
5791  val32 = std::max(val1,val32); val34 = std::max(val3,val34); val36 = std::max(val5,val36);
5792  val38 = std::max(val7,val38); val9 = std::min(val9,val40); val11 = std::min(val11,val42);
5793  val13 = std::min(val13,val44); val15 = std::min(val15,val46); val17 = std::min(val17,val48);
5794  val24 = std::max(val9,val24); val26 = std::max(val11,val26); val28 = std::max(val13,val28);
5795  val30 = std::max(val15,val30); val17 = std::min(val17,val32); val19 = std::min(val19,val34);
5796  val21 = std::min(val21,val36); val23 = std::min(val23,val38); val24 = std::max(val17,val24);
5797  val26 = std::max(val19,val26); val21 = std::min(val21,val28); val23 = std::min(val23,val30);
5798  val24 = std::max(val21,val24); val23 = std::min(val23,val26);
5799  return std::max(val23,val24);
5800  }
5801 
5803  template<typename T>
5804  inline T hypot(const T x, const T y) {
5805  return std::sqrt(x*x + y*y);
5806  }
5807 
5808  template<typename T>
5809  inline T hypot(const T x, const T y, const T z) {
5810  return std::sqrt(x*x + y*y + z*z);
5811  }
5812 
5813  template<typename T>
5814  inline T _hypot(const T x, const T y) { // Slower but more precise version
5815  T nx = cimg::abs(x), ny = cimg::abs(y), t;
5816  if (nx<ny) { t = nx; nx = ny; } else t = ny;
5817  if (nx>0) { t/=nx; return nx*std::sqrt(1 + t*t); }
5818  return 0;
5819  }
5820 
5822  inline double factorial(const int n) {
5823  if (n<0) return cimg::type<double>::nan();
5824  if (n<2) return 1;
5825  double res = 2;
5826  for (int i = 3; i<=n; ++i) res*=i;
5827  return res;
5828  }
5829 
5831  inline double permutations(const int k, const int n, const bool with_order) {
5832  if (n<0 || k<0) return cimg::type<double>::nan();
5833  if (k>n) return 0;
5834  double res = 1;
5835  for (int i = n; i>=n - k + 1; --i) res*=i;
5836  return with_order?res:res/cimg::factorial(k);
5837  }
5838 
5839  inline double _fibonacci(int exp) {
5840  double
5841  base = (1 + std::sqrt(5.0))/2,
5842  result = 1/std::sqrt(5.0);
5843  while (exp) {
5844  if (exp&1) result*=base;
5845  exp>>=1;
5846  base*=base;
5847  }
5848  return result;
5849  }
5850 
5852  // (Precise up to n = 78, less precise for n>78).
5853  inline double fibonacci(const int n) {
5854  if (n<0) return cimg::type<double>::nan();
5855  if (n<3) return 1;
5856  if (n<11) {
5857  cimg_uint64 fn1 = 1, fn2 = 1, fn = 0;
5858  for (int i = 3; i<=n; ++i) { fn = fn1 + fn2; fn2 = fn1; fn1 = fn; }
5859  return (double)fn;
5860  }
5861  if (n<75) // precise up to n = 74, faster than the integer calculation above for n>10
5862  return (double)((cimg_uint64)(_fibonacci(n) + 0.5));
5863 
5864  if (n<94) { // precise up to n = 78, less precise for n>78 up to n = 93, overflows for n>93
5865  cimg_uint64
5866  fn1 = (cimg_uint64)1304969544928657ULL,
5867  fn2 = (cimg_uint64)806515533049393ULL,
5868  fn = 0;
5869  for (int i = 75; i<=n; ++i) { fn = fn1 + fn2; fn2 = fn1; fn1 = fn; }
5870  return (double)fn;
5871  }
5872  return _fibonacci(n); // Not precise, but better than the wrong overflowing calculation
5873  }
5874 
5876  inline long gcd(long a, long b) {
5877  while (a) { const long c = a; a = b%a; b = c; }
5878  return b;
5879  }
5880 
5882  inline char lowercase(const char x) {
5883  return (char)((x<'A'||x>'Z')?x:x - 'A' + 'a');
5884  }
5885  inline double lowercase(const double x) {
5886  return (double)((x<'A'||x>'Z')?x:x - 'A' + 'a');
5887  }
5888 
5890  inline void lowercase(char *const str) {
5891  if (str) for (char *ptr = str; *ptr; ++ptr) *ptr = lowercase(*ptr);
5892  }
5893 
5895  inline char uppercase(const char x) {
5896  return (char)((x<'a'||x>'z')?x:x - 'a' + 'A');
5897  }
5898 
5899  inline double uppercase(const double x) {
5900  return (double)((x<'a'||x>'z')?x:x - 'a' + 'A');
5901  }
5902 
5904  inline void uppercase(char *const str) {
5905  if (str) for (char *ptr = str; *ptr; ++ptr) *ptr = uppercase(*ptr);
5906  }
5907 
5909 
5915  inline double atof(const char *const str) {
5916  double x = 0, y = 1;
5917  return str && cimg_sscanf(str,"%lf/%lf",&x,&y)>0?x/y:0;
5918  }
5919 
5921 
5928  inline int strncasecmp(const char *const str1, const char *const str2, const int l) {
5929  if (!l) return 0;
5930  if (!str1) return str2?-1:0;
5931  const char *nstr1 = str1, *nstr2 = str2;
5932  int k, diff = 0; for (k = 0; k<l && !(diff = lowercase(*nstr1) - lowercase(*nstr2)); ++k) { ++nstr1; ++nstr2; }
5933  return k!=l?diff:0;
5934  }
5935 
5937 
5943  inline int strcasecmp(const char *const str1, const char *const str2) {
5944  if (!str1) return str2?-1:0;
5945  const int
5946  l1 = (int)std::strlen(str1),
5947  l2 = (int)std::strlen(str2);
5948  return cimg::strncasecmp(str1,str2,1 + (l1<l2?l1:l2));
5949  }
5950 
5952 
5957  inline char *strellipsize(char *const str, const unsigned int l=64,
5958  const bool is_ending=true) {
5959  if (!str) return str;
5960  const unsigned int nl = l<5?5:l, ls = (unsigned int)std::strlen(str);
5961  if (ls<=nl) return str;
5962  if (is_ending) std::strcpy(str + nl - 5,"(...)");
5963  else {
5964  const unsigned int ll = (nl - 5)/2 + 1 - (nl%2), lr = nl - ll - 5;
5965  std::strcpy(str + ll,"(...)");
5966  std::memmove(str + ll + 5,str + ls - lr,lr);
5967  }
5968  str[nl] = 0;
5969  return str;
5970  }
5971 
5973 
5979  inline char *strellipsize(const char *const str, char *const res, const unsigned int l=64,
5980  const bool is_ending=true) {
5981  const unsigned int nl = l<5?5:l, ls = (unsigned int)std::strlen(str);
5982  if (ls<=nl) { std::strcpy(res,str); return res; }
5983  if (is_ending) {
5984  std::strncpy(res,str,nl - 5);
5985  std::strcpy(res + nl -5,"(...)");
5986  } else {
5987  const unsigned int ll = (nl - 5)/2 + 1 - (nl%2), lr = nl - ll - 5;
5988  std::strncpy(res,str,ll);
5989  std::strcpy(res + ll,"(...)");
5990  std::strncpy(res + ll + 5,str + ls - lr,lr);
5991  }
5992  res[nl] = 0;
5993  return res;
5994  }
5995 
5997 
6005  inline bool strpare(char *const str, const char delimiter,
6006  const bool is_symmetric, const bool is_iterative) {
6007  if (!str) return false;
6008  const int l = (int)std::strlen(str);
6009  int p, q;
6010  if (is_symmetric) for (p = 0, q = l - 1; p<q && str[p]==delimiter && str[q]==delimiter; ) {
6011  --q; ++p; if (!is_iterative) break;
6012  } else {
6013  for (p = 0; p<l && str[p]==delimiter; ) { ++p; if (!is_iterative) break; }
6014  for (q = l - 1; q>p && str[q]==delimiter; ) { --q; if (!is_iterative) break; }
6015  }
6016  const int n = q - p + 1;
6017  if (n!=l) { std::memmove(str,str + p,(unsigned int)n); str[n] = 0; return true; }
6018  return false;
6019  }
6020 
6022  inline bool strpare(char *const str, const bool is_symmetric, const bool is_iterative) {
6023  if (!str) return false;
6024  const int l = (int)std::strlen(str);
6025  int p, q;
6026  if (is_symmetric) for (p = 0, q = l - 1; p<q && (signed char)str[p]<=' ' && (signed char)str[q]<=' '; ) {
6027  --q; ++p; if (!is_iterative) break;
6028  } else {
6029  for (p = 0; p<l && (signed char)str[p]<=' '; ) { ++p; if (!is_iterative) break; }
6030  for (q = l - 1; q>p && (signed char)str[q]<=' '; ) { --q; if (!is_iterative) break; }
6031  }
6032  const int n = q - p + 1;
6033  if (n!=l) { std::memmove(str,str + p,(unsigned int)n); str[n] = 0; return true; }
6034  return false;
6035  }
6036 
6038 
6042  inline void strwindows_reserved(char *const str, const char c='_') {
6043  for (char *s = str; *s; ++s) {
6044  const char i = *s;
6045  if (i=='<' || i=='>' || i==':' || i=='\"' || i=='/' || i=='\\' || i=='|' || i=='?' || i=='*') *s = c;
6046  }
6047  }
6048 
6050 
6053  inline void strunescape(char *const str) {
6054 #define cimg_strunescape(ci,co) case ci : *nd = co; ++ns; break;
6055  unsigned int val = 0;
6056  for (char *ns = str, *nd = str; *ns || (bool)(*nd=0); ++nd) if (*ns=='\\') switch (*(++ns)) {
6057  cimg_strunescape('a','\a');
6058  cimg_strunescape('b','\b');
6059  cimg_strunescape('e',0x1B);
6060  cimg_strunescape('f','\f');
6061  cimg_strunescape('n','\n');
6062  cimg_strunescape('r','\r');
6063  cimg_strunescape('t','\t');
6064  cimg_strunescape('v','\v');
6065  cimg_strunescape('\\','\\');
6066  cimg_strunescape('\'','\'');
6067  cimg_strunescape('\"','\"');
6068  cimg_strunescape('\?','\?');
6069  case 0 : *nd = 0; break;
6070  case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' :
6071  cimg_sscanf(ns,"%o",&val); while (*ns>='0' && *ns<='7') ++ns;
6072  *nd = (char)val; break;
6073  case 'x' :
6074  cimg_sscanf(++ns,"%x",&val);
6075  while ((*ns>='0' && *ns<='9') || (*ns>='a' && *ns<='f') || (*ns>='A' && *ns<='F')) ++ns;
6076  *nd = (char)val; break;
6077  default : *nd = *(ns++);
6078  } else *nd = *(ns++);
6079  }
6080 
6081  // Return a temporary string describing the size of a memory buffer.
6082  inline const char *strbuffersize(const cimg_ulong size);
6083 
6084  // Return string that identifies the running OS.
6085  inline const char *stros() {
6086 #if defined(linux) || defined(__linux) || defined(__linux__)
6087  static const char *const str = "Linux";
6088 #elif defined(sun) || defined(__sun)
6089  static const char *const str = "Sun OS";
6090 #elif defined(BSD) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined (__DragonFly__)
6091  static const char *const str = "BSD";
6092 #elif defined(sgi) || defined(__sgi)
6093  static const char *const str = "Irix";
6094 #elif defined(__MACOSX__) || defined(__APPLE__)
6095  static const char *const str = "Mac OS";
6096 #elif defined(unix) || defined(__unix) || defined(__unix__)
6097  static const char *const str = "Generic Unix";
6098 #elif defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || \
6099  defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
6100  static const char *const str = "Windows";
6101 #else
6102  const char
6103  *const _str1 = std::getenv("OSTYPE"),
6104  *const _str2 = _str1?_str1:std::getenv("OS"),
6105  *const str = _str2?_str2:"Unknown OS";
6106 #endif
6107  return str;
6108  }
6109 
6111  inline const char* basename(const char *const s, const char separator=cimg_file_separator) {
6112  const char *p = 0, *np = s;
6113  while (np>=s && (p=np)) np = std::strchr(np,separator) + 1;
6114  return p;
6115  }
6116 
6117  // Return a random filename.
6118  inline const char* filenamerand() {
6119  cimg::mutex(6);
6120  static char randomid[9];
6121  cimg::srand();
6122  for (unsigned int k = 0; k<8; ++k) {
6123  const int v = (int)cimg::rand(65535)%3;
6124  randomid[k] = (char)(v==0?('0' + ((int)cimg::rand(65535)%10)):
6125  (v==1?('a' + ((int)cimg::rand(65535)%26)):
6126  ('A' + ((int)cimg::rand(65535)%26))));
6127  }
6128  cimg::mutex(6,0);
6129  return randomid;
6130  }
6131 
6132  // Convert filename as a Windows-style filename (short path name).
6133  inline void winformat_string(char *const str) {
6134  if (str && *str) {
6135 #if cimg_OS==2
6136  char *const nstr = new char[MAX_PATH];
6137  if (GetShortPathNameA(str,nstr,MAX_PATH)) std::strcpy(str,nstr);
6138  delete[] nstr;
6139 #endif
6140  }
6141  }
6142 
6143  // Open a file (with wide character support on Windows).
6144  inline std::FILE *win_fopen(const char *const path, const char *const mode);
6145 
6147 
6154  inline std::FILE *fopen(const char *const path, const char *const mode) {
6155  if (!path)
6156  throw CImgArgumentException("cimg::fopen(): Specified file path is (null).");
6157  if (!mode)
6158  throw CImgArgumentException("cimg::fopen(): File '%s', specified mode is (null).",
6159  path);
6160  std::FILE *res = 0;
6161  if (*path=='-' && (!path[1] || path[1]=='.')) {
6162  res = (*mode=='r')?cimg::_stdin():cimg::_stdout();
6163 #if cimg_OS==2
6164  if (*mode && mode[1]=='b') { // Force stdin/stdout to be in binary mode.
6165 #ifdef __BORLANDC__
6166  if (setmode(_fileno(res),0x8000)==-1) res = 0;
6167 #else
6168  if (_setmode(_fileno(res),0x8000)==-1) res = 0;
6169 #endif
6170  }
6171 #endif
6172  } else res = std_fopen(path,mode);
6173  if (!res) throw CImgIOException("cimg::fopen(): Failed to open file '%s' with mode '%s'.",
6174  path,mode);
6175  return res;
6176  }
6177 
6179 
6185  inline int fclose(std::FILE *file) {
6186  if (!file) { warn("cimg::fclose(): Specified file is (null)."); return 0; }
6187  if (file==cimg::_stdin(false) || file==cimg::_stdout(false)) return 0;
6188  const int errn = std::fclose(file);
6189  if (errn!=0) warn("cimg::fclose(): Error code %d returned during file closing.",
6190  errn);
6191  return errn;
6192  }
6193 
6195  inline int fseek(FILE *stream, cimg_long offset, int origin) {
6196 #if defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
6197  return _fseeki64(stream,(__int64)offset,origin);
6198 #else
6199  return std::fseek(stream,offset,origin);
6200 #endif
6201  }
6202 
6204  inline cimg_long ftell(FILE *stream) {
6205 #if defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
6206  return (cimg_long)_ftelli64(stream);
6207 #else
6208  return (cimg_long)std::ftell(stream);
6209 #endif
6210  }
6211 
6213 
6216  inline bool is_directory(const char *const path) {
6217  if (!path || !*path) return false;
6218 #if cimg_OS==1
6219  struct stat st_buf;
6220  return (!stat(path,&st_buf) && S_ISDIR(st_buf.st_mode));
6221 #elif cimg_OS==2
6222  const unsigned int res = (unsigned int)GetFileAttributesA(path);
6223  return res==INVALID_FILE_ATTRIBUTES?false:(res&16);
6224 #else
6225  return false;
6226 #endif
6227  }
6228 
6230 
6233  inline bool is_file(const char *const path) {
6234  if (!path || !*path) return false;
6235  std::FILE *const file = std_fopen(path,"rb");
6236  if (!file) return false;
6237  std::fclose(file);
6238  return !is_directory(path);
6239  }
6240 
6242 
6246  inline cimg_int64 fsize(const char *const filename) {
6247  std::FILE *const file = std::fopen(filename,"rb");
6248  if (!file) return (cimg_int64)-1;
6249  std::fseek(file,0,SEEK_END);
6250  const cimg_int64 siz = (cimg_int64)std::ftell(file);
6251  std::fclose(file);
6252  return siz;
6253  }
6254 
6256 
6264  template<typename T>
6265  inline int fdate(const char *const path, T *attr, const unsigned int nb_attr) {
6266 #define _cimg_fdate_err() for (unsigned int i = 0; i<nb_attr; ++i) attr[i] = (T)-1
6267  int res = -1;
6268  if (!path || !*path) { _cimg_fdate_err(); return -1; }
6269  cimg::mutex(6);
6270 #if cimg_OS==2
6271  HANDLE file = CreateFileA(path,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
6272  if (file!=INVALID_HANDLE_VALUE) {
6273  FILETIME _ft;
6274  SYSTEMTIME ft;
6275  if (GetFileTime(file,0,0,&_ft) && FileTimeToSystemTime(&_ft,&ft)) {
6276  for (unsigned int i = 0; i<nb_attr; ++i) {
6277  res = (int)(attr[i]==0?ft.wYear:attr[i]==1?ft.wMonth:attr[i]==2?ft.wDay:
6278  attr[i]==3?ft.wDayOfWeek:attr[i]==4?ft.wHour:attr[i]==5?ft.wMinute:
6279  attr[i]==6?ft.wSecond:-1);
6280  attr[i] = (T)res;
6281  }
6282  } else _cimg_fdate_err();
6283  CloseHandle(file);
6284  } else _cimg_fdate_err();
6285 #elif cimg_OS==1
6286  struct stat st_buf;
6287  if (!stat(path,&st_buf)) {
6288  const time_t _ft = st_buf.st_mtime;
6289  const struct tm& ft = *std::localtime(&_ft);
6290  for (unsigned int i = 0; i<nb_attr; ++i) {
6291  res = (int)(attr[i]==0?ft.tm_year + 1900:attr[i]==1?ft.tm_mon + 1:attr[i]==2?ft.tm_mday:
6292  attr[i]==3?ft.tm_wday:attr[i]==4?ft.tm_hour:attr[i]==5?ft.tm_min:
6293  attr[i]==6?ft.tm_sec:-1);
6294  attr[i] = (T)res;
6295  }
6296  } else _cimg_fdate_err();
6297 #endif
6298  cimg::mutex(6,0);
6299  return res;
6300  }
6301 
6303 
6309  inline int fdate(const char *const path, unsigned int attr) {
6310  int out = (int)attr;
6311  return fdate(path,&out,1);
6312  }
6313 
6315 
6322  template<typename T>
6323  inline int date(T *attr, const unsigned int nb_attr) {
6324  int res = -1;
6325  cimg::mutex(6);
6326 #if cimg_OS==2
6327  SYSTEMTIME st;
6328  GetLocalTime(&st);
6329  for (unsigned int i = 0; i<nb_attr; ++i) {
6330  res = (int)(attr[i]==0?st.wYear:attr[i]==1?st.wMonth:attr[i]==2?st.wDay:
6331  attr[i]==3?st.wDayOfWeek:attr[i]==4?st.wHour:attr[i]==5?st.wMinute:
6332  attr[i]==6?st.wSecond:-1);
6333  attr[i] = (T)res;
6334  }
6335 #else
6336  time_t _st;
6337  std::time(&_st);
6338  struct tm *st = std::localtime(&_st);
6339  for (unsigned int i = 0; i<nb_attr; ++i) {
6340  res = (int)(attr[i]==0?st->tm_year + 1900:attr[i]==1?st->tm_mon + 1:attr[i]==2?st->tm_mday:
6341  attr[i]==3?st->tm_wday:attr[i]==4?st->tm_hour:attr[i]==5?st->tm_min:
6342  attr[i]==6?st->tm_sec:-1);
6343  attr[i] = (T)res;
6344  }
6345 #endif
6346  cimg::mutex(6,0);
6347  return res;
6348  }
6349 
6351 
6356  inline int date(unsigned int attr) {
6357  int out = (int)attr;
6358  return date(&out,1);
6359  }
6360 
6361  // Get/set path to store temporary files.
6362  inline const char* temporary_path(const char *const user_path=0, const bool reinit_path=false);
6363 
6364  // Get/set path to the <i>Program Files/</i> directory (Windows only).
6365 #if cimg_OS==2
6366  inline const char* programfiles_path(const char *const user_path=0, const bool reinit_path=false);
6367 #endif
6368 
6369  // Get/set path to the ImageMagick's \c convert binary.
6370  inline const char* imagemagick_path(const char *const user_path=0, const bool reinit_path=false);
6371 
6372  // Get/set path to the GraphicsMagick's \c gm binary.
6373  inline const char* graphicsmagick_path(const char *const user_path=0, const bool reinit_path=false);
6374 
6375  // Get/set path to the XMedcon's \c medcon binary.
6376  inline const char* medcon_path(const char *const user_path=0, const bool reinit_path=false);
6377 
6378  // Get/set path to the FFMPEG's \c ffmpeg binary.
6379  inline const char *ffmpeg_path(const char *const user_path=0, const bool reinit_path=false);
6380 
6381  // Get/set path to the \c gzip binary.
6382  inline const char *gzip_path(const char *const user_path=0, const bool reinit_path=false);
6383 
6384  // Get/set path to the \c gunzip binary.
6385  inline const char *gunzip_path(const char *const user_path=0, const bool reinit_path=false);
6386 
6387  // Get/set path to the \c dcraw binary.
6388  inline const char *dcraw_path(const char *const user_path=0, const bool reinit_path=false);
6389 
6390  // Get/set path to the \c wget binary.
6391  inline const char *wget_path(const char *const user_path=0, const bool reinit_path=false);
6392 
6393  // Get/set path to the \c curl binary.
6394  inline const char *curl_path(const char *const user_path=0, const bool reinit_path=false);
6395 
6397 
6400  inline const char *split_filename(const char *const filename, char *const body=0) {
6401  if (!filename) { if (body) *body = 0; return 0; }
6402  const char *p = 0; for (const char *np = filename; np>=filename && (p=np); np = std::strchr(np,'.') + 1) {}
6403  if (p==filename) {
6404  if (body) std::strcpy(body,filename);
6405  return filename + std::strlen(filename);
6406  }
6407  const unsigned int l = (unsigned int)(p - filename - 1);
6408  if (body) { if (l) std::memcpy(body,filename,l); body[l] = 0; }
6409  return p;
6410  }
6411 
6413  inline char* number_filename(const char *const filename, const int number,
6414  const unsigned int digits, char *const str) {
6415  if (!filename) { if (str) *str = 0; return 0; }
6416  char *const format = new char[1024], *const body = new char[1024];
6417  const char *const ext = cimg::split_filename(filename,body);
6418  if (*ext) cimg_snprintf(format,1024,"%%s_%%.%ud.%%s",digits);
6419  else cimg_snprintf(format,1024,"%%s_%%.%ud",digits);
6420  cimg_sprintf(str,format,body,number,ext);
6421  delete[] format; delete[] body;
6422  return str;
6423  }
6424 
6426 
6433  template<typename T>
6434  inline size_t fread(T *const ptr, const size_t nmemb, std::FILE *stream) {
6435  if (!ptr || !stream)
6436  throw CImgArgumentException("cimg::fread(): Invalid reading request of %u %s%s from file %p to buffer %p.",
6437  nmemb,cimg::type<T>::string(),nmemb>1?"s":"",stream,ptr);
6438  if (!nmemb) return 0;
6439  const size_t wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);
6440  size_t to_read = nmemb, al_read = 0, l_to_read = 0, l_al_read = 0;
6441  do {
6442  l_to_read = (to_read*sizeof(T))<wlimitT?to_read:wlimit;
6443  l_al_read = std::fread((void*)(ptr + al_read),sizeof(T),l_to_read,stream);
6444  al_read+=l_al_read;
6445  to_read-=l_al_read;
6446  } while (l_to_read==l_al_read && to_read>0);
6447  if (to_read>0)
6448  warn("cimg::fread(): Only %lu/%lu elements could be read from file.",
6449  (unsigned long)al_read,(unsigned long)nmemb);
6450  return al_read;
6451  }
6452 
6454 
6461  template<typename T>
6462  inline size_t fwrite(const T *ptr, const size_t nmemb, std::FILE *stream) {
6463  if (!ptr || !stream)
6464  throw CImgArgumentException("cimg::fwrite(): Invalid writing request of %u %s%s from buffer %p to file %p.",
6465  nmemb,cimg::type<T>::string(),nmemb>1?"s":"",ptr,stream);
6466  if (!nmemb) return 0;
6467  const size_t wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);
6468  size_t to_write = nmemb, al_write = 0, l_to_write = 0, l_al_write = 0;
6469  do {
6470  l_to_write = (to_write*sizeof(T))<wlimitT?to_write:wlimit;
6471  l_al_write = std::fwrite((void*)(ptr + al_write),sizeof(T),l_to_write,stream);
6472  al_write+=l_al_write;
6473  to_write-=l_al_write;
6474  } while (l_to_write==l_al_write && to_write>0);
6475  if (to_write>0)
6476  warn("cimg::fwrite(): Only %lu/%lu elements could be written in file.",
6477  (unsigned long)al_write,(unsigned long)nmemb);
6478  return al_write;
6479  }
6480 
6482 
6486  inline void fempty(std::FILE *const file, const char *const filename) {
6487  if (!file && !filename)
6488  throw CImgArgumentException("cimg::fempty(): Specified filename is (null).");
6489  std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
6490  if (!file) cimg::fclose(nfile);
6491  }
6492 
6493  // Try to guess format from an image file.
6494  inline const char *ftype(std::FILE *const file, const char *const filename);
6495 
6496  // Load file from network as a local temporary file.
6497  inline char *load_network(const char *const url, char *const filename_local,
6498  const unsigned int timeout=0, const bool try_fallback=false,
6499  const char *const referer=0);
6500 
6502  inline const char* option(const char *const name, const int argc, const char *const *const argv,
6503  const char *const defaut, const char *const usage, const bool reset_static) {
6504  static bool first = true, visu = false;
6505  if (reset_static) { first = true; return 0; }
6506  const char *res = 0;
6507  if (first) {
6508  first = false;
6509  visu = cimg::option("-h",argc,argv,(char*)0,(char*)0,false)!=0;
6510  visu |= cimg::option("-help",argc,argv,(char*)0,(char*)0,false)!=0;
6511  visu |= cimg::option("--help",argc,argv,(char*)0,(char*)0,false)!=0;
6512  }
6513  if (!name && visu) {
6514  if (usage) {
6515  std::fprintf(cimg::output(),"\n %s%s%s",cimg::t_red,cimg::basename(argv[0]),cimg::t_normal);
6516  std::fprintf(cimg::output(),": %s",usage);
6517  std::fprintf(cimg::output()," (%s, %s)\n\n",cimg_date,cimg_time);
6518  }
6519  if (defaut) std::fprintf(cimg::output(),"%s\n",defaut);
6520  }
6521  if (name) {
6522  if (argc>0) {
6523  int k = 0;
6524  while (k<argc && std::strcmp(argv[k],name)) ++k;
6525  res = (k++==argc?defaut:(k==argc?argv[--k]:argv[k]));
6526  } else res = defaut;
6527  if (visu && usage) std::fprintf(cimg::output()," %s%-16s%s %-24s %s%s%s\n",
6528  cimg::t_bold,name,cimg::t_normal,res?res:"0",
6529  cimg::t_green,usage,cimg::t_normal);
6530  }
6531  return res;
6532  }
6533 
6534  inline const char* option(const char *const name, const int argc, const char *const *const argv,
6535  const char *const defaut, const char *const usage=0) {
6536  return option(name,argc,argv,defaut,usage,false);
6537  }
6538 
6539  inline bool option(const char *const name, const int argc, const char *const *const argv,
6540  const bool defaut, const char *const usage=0) {
6541  const char *const s = cimg::option(name,argc,argv,(char*)0);
6542  const bool res = s?(cimg::strcasecmp(s,"false") && cimg::strcasecmp(s,"off") && cimg::strcasecmp(s,"0")):defaut;
6543  cimg::option(name,0,0,res?"true":"false",usage);
6544  return res;
6545  }
6546 
6547  inline int option(const char *const name, const int argc, const char *const *const argv,
6548  const int defaut, const char *const usage=0) {
6549  const char *const s = cimg::option(name,argc,argv,(char*)0);
6550  const int res = s?std::atoi(s):defaut;
6551  char *const tmp = new char[256];
6552  cimg_snprintf(tmp,256,"%d",res);
6553  cimg::option(name,0,0,tmp,usage);
6554  delete[] tmp;
6555  return res;
6556  }
6557 
6558  inline char option(const char *const name, const int argc, const char *const *const argv,
6559  const char defaut, const char *const usage=0) {
6560  const char *const s = cimg::option(name,argc,argv,(char*)0);
6561  const char res = s?*s:defaut;
6562  char tmp[8];
6563  *tmp = res; tmp[1] = 0;
6564  cimg::option(name,0,0,tmp,usage);
6565  return res;
6566  }
6567 
6568  inline float option(const char *const name, const int argc, const char *const *const argv,
6569  const float defaut, const char *const usage=0) {
6570  const char *const s = cimg::option(name,argc,argv,(char*)0);
6571  const float res = s?(float)cimg::atof(s):defaut;
6572  char *const tmp = new char[256];
6573  cimg_snprintf(tmp,256,"%g",res);
6574  cimg::option(name,0,0,tmp,usage);
6575  delete[] tmp;
6576  return res;
6577  }
6578 
6579  inline double option(const char *const name, const int argc, const char *const *const argv,
6580  const double defaut, const char *const usage=0) {
6581  const char *const s = cimg::option(name,argc,argv,(char*)0);
6582  const double res = s?cimg::atof(s):defaut;
6583  char *const tmp = new char[256];
6584  cimg_snprintf(tmp,256,"%g",res);
6585  cimg::option(name,0,0,tmp,usage);
6586  delete[] tmp;
6587  return res;
6588  }
6589 
6591 
6594  inline void info() {
6595  std::fprintf(cimg::output(),"\n %s%sCImg Library %u.%u.%u%s, compiled %s ( %s ) with the following flags:\n\n",
6596  cimg::t_red,cimg::t_bold,cimg_version/100,(cimg_version/10)%10,cimg_version%10,
6597  cimg::t_normal,cimg_date,cimg_time);
6598 
6599  std::fprintf(cimg::output()," > Operating System: %s%-13s%s %s('cimg_OS'=%d)%s\n",
6600  cimg::t_bold,
6601  cimg_OS==1?"Unix":(cimg_OS==2?"Windows":"Unknow"),
6602  cimg::t_normal,cimg::t_green,
6603  cimg_OS,
6604  cimg::t_normal);
6605 
6606  std::fprintf(cimg::output()," > CPU endianness: %s%s Endian%s\n",
6607  cimg::t_bold,
6608  cimg::endianness()?"Big":"Little",
6609  cimg::t_normal);
6610 
6611  std::fprintf(cimg::output()," > Verbosity mode: %s%-13s%s %s('cimg_verbosity'=%d)%s\n",
6612  cimg::t_bold,
6613  cimg_verbosity==0?"Quiet":
6614  cimg_verbosity==1?"Console":
6615  cimg_verbosity==2?"Dialog":
6616  cimg_verbosity==3?"Console+Warnings":"Dialog+Warnings",
6617  cimg::t_normal,cimg::t_green,
6618  cimg_verbosity,
6619  cimg::t_normal);
6620 
6621  std::fprintf(cimg::output()," > Stricts warnings: %s%-13s%s %s('cimg_strict_warnings' %s)%s\n",
6622  cimg::t_bold,
6623 #ifdef cimg_strict_warnings
6624  "Yes",cimg::t_normal,cimg::t_green,"defined",
6625 #else
6626  "No",cimg::t_normal,cimg::t_green,"undefined",
6627 #endif
6628  cimg::t_normal);
6629 
6630  std::fprintf(cimg::output()," > Support for C++11: %s%-13s%s %s('cimg_use_cpp11'=%d)%s\n",
6631  cimg::t_bold,
6632  cimg_use_cpp11?"Yes":"No",
6633  cimg::t_normal,cimg::t_green,
6634  (int)cimg_use_cpp11,
6635  cimg::t_normal);
6636 
6637  std::fprintf(cimg::output()," > Using VT100 messages: %s%-13s%s %s('cimg_use_vt100' %s)%s\n",
6638  cimg::t_bold,
6639 #ifdef cimg_use_vt100
6640  "Yes",cimg::t_normal,cimg::t_green,"defined",
6641 #else
6642  "No",cimg::t_normal,cimg::t_green,"undefined",
6643 #endif
6644  cimg::t_normal);
6645 
6646  std::fprintf(cimg::output()," > Display type: %s%-13s%s %s('cimg_display'=%d)%s\n",
6647  cimg::t_bold,
6648  cimg_display==0?"No display":cimg_display==1?"X11":cimg_display==2?"Windows GDI":"Unknown",
6649  cimg::t_normal,cimg::t_green,
6650  (int)cimg_display,
6651  cimg::t_normal);
6652 
6653 #if cimg_display==1
6654  std::fprintf(cimg::output()," > Using XShm for X11: %s%-13s%s %s('cimg_use_xshm' %s)%s\n",
6655  cimg::t_bold,
6656 #ifdef cimg_use_xshm
6657  "Yes",cimg::t_normal,cimg::t_green,"defined",
6658 #else
6659  "No",cimg::t_normal,cimg::t_green,"undefined",
6660 #endif
6661  cimg::t_normal);
6662 
6663  std::fprintf(cimg::output()," > Using XRand for X11: %s%-13s%s %s('cimg_use_xrandr' %s)%s\n",
6664  cimg::t_bold,
6665 #ifdef cimg_use_xrandr
6666  "Yes",cimg::t_normal,cimg::t_green,"defined",
6667 #else
6668  "No",cimg::t_normal,cimg::t_green,"undefined",
6669 #endif
6670  cimg::t_normal);
6671 #endif
6672  std::fprintf(cimg::output()," > Using OpenMP: %s%-13s%s %s('cimg_use_openmp' %s)%s\n",
6673  cimg::t_bold,
6674 #ifdef cimg_use_openmp
6675  "Yes",cimg::t_normal,cimg::t_green,"defined",
6676 #else
6677  "No",cimg::t_normal,cimg::t_green,"undefined",
6678 #endif
6679  cimg::t_normal);
6680  std::fprintf(cimg::output()," > Using PNG library: %s%-13s%s %s('cimg_use_png' %s)%s\n",
6681  cimg::t_bold,
6682 #ifdef cimg_use_png
6683  "Yes",cimg::t_normal,cimg::t_green,"defined",
6684 #else
6685  "No",cimg::t_normal,cimg::t_green,"undefined",
6686 #endif
6687  cimg::t_normal);
6688  std::fprintf(cimg::output()," > Using JPEG library: %s%-13s%s %s('cimg_use_jpeg' %s)%s\n",
6689  cimg::t_bold,
6690 #ifdef cimg_use_jpeg
6691  "Yes",cimg::t_normal,cimg::t_green,"defined",
6692 #else
6693  "No",cimg::t_normal,cimg::t_green,"undefined",
6694 #endif
6695  cimg::t_normal);
6696 
6697  std::fprintf(cimg::output()," > Using TIFF library: %s%-13s%s %s('cimg_use_tiff' %s)%s\n",
6698  cimg::t_bold,
6699 #ifdef cimg_use_tiff
6700  "Yes",cimg::t_normal,cimg::t_green,"defined",
6701 #else
6702  "No",cimg::t_normal,cimg::t_green,"undefined",
6703 #endif
6704  cimg::t_normal);
6705 
6706  std::fprintf(cimg::output()," > Using Magick++ library: %s%-13s%s %s('cimg_use_magick' %s)%s\n",
6707  cimg::t_bold,
6708 #ifdef cimg_use_magick
6709  "Yes",cimg::t_normal,cimg::t_green,"defined",
6710 #else
6711  "No",cimg::t_normal,cimg::t_green,"undefined",
6712 #endif
6713  cimg::t_normal);
6714 
6715  std::fprintf(cimg::output()," > Using FFTW3 library: %s%-13s%s %s('cimg_use_fftw3' %s)%s\n",
6716  cimg::t_bold,
6717 #ifdef cimg_use_fftw3
6718  "Yes",cimg::t_normal,cimg::t_green,"defined",
6719 #else
6720  "No",cimg::t_normal,cimg::t_green,"undefined",
6721 #endif
6722  cimg::t_normal);
6723 
6724  std::fprintf(cimg::output()," > Using LAPACK library: %s%-13s%s %s('cimg_use_lapack' %s)%s\n",
6725  cimg::t_bold,
6726 #ifdef cimg_use_lapack
6727  "Yes",cimg::t_normal,cimg::t_green,"defined",
6728 #else
6729  "No",cimg::t_normal,cimg::t_green,"undefined",
6730 #endif
6731  cimg::t_normal);
6732 
6733  char *const tmp = new char[1024];
6734  cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::imagemagick_path());
6735  std::fprintf(cimg::output()," > Path of ImageMagick: %s%-13s%s\n",
6736  cimg::t_bold,
6737  tmp,
6738  cimg::t_normal);
6739 
6740  cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::graphicsmagick_path());
6741  std::fprintf(cimg::output()," > Path of GraphicsMagick: %s%-13s%s\n",
6742  cimg::t_bold,
6743  tmp,
6744  cimg::t_normal);
6745 
6746  cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::medcon_path());
6747  std::fprintf(cimg::output()," > Path of 'medcon': %s%-13s%s\n",
6748  cimg::t_bold,
6749  tmp,
6750  cimg::t_normal);
6751 
6752  cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::temporary_path());
6753  std::fprintf(cimg::output()," > Temporary path: %s%-13s%s\n",
6754  cimg::t_bold,
6755  tmp,
6756  cimg::t_normal);
6757 
6758  std::fprintf(cimg::output(),"\n");
6759  delete[] tmp;
6760  }
6761 
6762  // Declare LAPACK function signatures if LAPACK support is enabled.
6763 #ifdef cimg_use_lapack
6764  template<typename T>
6765  inline void getrf(int &N, T *lapA, int *IPIV, int &INFO) {
6766  dgetrf_(&N,&N,lapA,&N,IPIV,&INFO);
6767  }
6768 
6769  inline void getrf(int &N, float *lapA, int *IPIV, int &INFO) {
6770  sgetrf_(&N,&N,lapA,&N,IPIV,&INFO);
6771  }
6772 
6773  template<typename T>
6774  inline void getri(int &N, T *lapA, int *IPIV, T* WORK, int &LWORK, int &INFO) {
6775  dgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);
6776  }
6777 
6778  inline void getri(int &N, float *lapA, int *IPIV, float* WORK, int &LWORK, int &INFO) {
6779  sgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);
6780  }
6781 
6782  template<typename T>
6783  inline void gesvd(char &JOB, int &M, int &N, T *lapA, int &MN,
6784  T *lapS, T *lapU, T *lapV, T *WORK, int &LWORK, int &INFO) {
6785  dgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);
6786  }
6787 
6788  inline void gesvd(char &JOB, int &M, int &N, float *lapA, int &MN,
6789  float *lapS, float *lapU, float *lapV, float *WORK, int &LWORK, int &INFO) {
6790  sgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);
6791  }
6792 
6793  template<typename T>
6794  inline void getrs(char &TRANS, int &N, T *lapA, int *IPIV, T *lapB, int &INFO) {
6795  int one = 1;
6796  dgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);
6797  }
6798 
6799  inline void getrs(char &TRANS, int &N, float *lapA, int *IPIV, float *lapB, int &INFO) {
6800  int one = 1;
6801  sgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);
6802  }
6803 
6804  template<typename T>
6805  inline void syev(char &JOB, char &UPLO, int &N, T *lapA, T *lapW, T *WORK, int &LWORK, int &INFO) {
6806  dsyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);
6807  }
6808 
6809  inline void syev(char &JOB, char &UPLO, int &N, float *lapA, float *lapW, float *WORK, int &LWORK, int &INFO) {
6810  ssyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);
6811  }
6812 
6813  template<typename T>
6814  inline void sgels(char & TRANS, int &M, int &N, int &NRHS, T* lapA, int &LDA,
6815  T* lapB, int &LDB, T* WORK, int &LWORK, int &INFO){
6816  dgels_(&TRANS, &M, &N, &NRHS, lapA, &LDA, lapB, &LDB, WORK, &LWORK, &INFO);
6817  }
6818 
6819  inline void sgels(char & TRANS, int &M, int &N, int &NRHS, float* lapA, int &LDA,
6820  float* lapB, int &LDB, float* WORK, int &LWORK, int &INFO){
6821  sgels_(&TRANS, &M, &N, &NRHS, lapA, &LDA, lapB, &LDB, WORK, &LWORK, &INFO);
6822  }
6823 
6824 #endif
6825 
6826  // End of the 'cimg' namespace
6827  }
6828 
6829  /*------------------------------------------------
6830  #
6831  #
6832  # Definition of mathematical operators and
6833  # external functions.
6834  #
6835  #
6836  -------------------------------------------------*/
6837 
6838 #define _cimg_create_ext_operators(typ) \
6839  template<typename T> \
6840  inline CImg<typename cimg::superset<T,typ>::type> operator+(const typ val, const CImg<T>& img) { \
6841  return img + val; \
6842  } \
6843  template<typename T> \
6844  inline CImg<typename cimg::superset<T,typ>::type> operator-(const typ val, const CImg<T>& img) { \
6845  typedef typename cimg::superset<T,typ>::type Tt; \
6846  return CImg<Tt>(img._width,img._height,img._depth,img._spectrum,val)-=img; \
6847  } \
6848  template<typename T> \
6849  inline CImg<typename cimg::superset<T,typ>::type> operator*(const typ val, const CImg<T>& img) { \
6850  return img*val; \
6851  } \
6852  template<typename T> \
6853  inline CImg<typename cimg::superset<T,typ>::type> operator/(const typ val, const CImg<T>& img) { \
6854  return val*img.get_invert(); \
6855  } \
6856  template<typename T> \
6857  inline CImg<typename cimg::superset<T,typ>::type> operator&(const typ val, const CImg<T>& img) { \
6858  return img & val; \
6859  } \
6860  template<typename T> \
6861  inline CImg<typename cimg::superset<T,typ>::type> operator|(const typ val, const CImg<T>& img) { \
6862  return img | val; \
6863  } \
6864  template<typename T> \
6865  inline CImg<typename cimg::superset<T,typ>::type> operator^(const typ val, const CImg<T>& img) { \
6866  return img ^ val; \
6867  } \
6868  template<typename T> \
6869  inline bool operator==(const typ val, const CImg<T>& img) { \
6870  return img == val; \
6871  } \
6872  template<typename T> \
6873  inline bool operator!=(const typ val, const CImg<T>& img) { \
6874  return img != val; \
6875  }
6876 
6877  _cimg_create_ext_operators(bool)
6878  _cimg_create_ext_operators(unsigned char)
6879  _cimg_create_ext_operators(char)
6880  _cimg_create_ext_operators(signed char)
6881  _cimg_create_ext_operators(unsigned short)
6882  _cimg_create_ext_operators(short)
6883  _cimg_create_ext_operators(unsigned int)
6884  _cimg_create_ext_operators(int)
6885  _cimg_create_ext_operators(cimg_uint64)
6886  _cimg_create_ext_operators(cimg_int64)
6887  _cimg_create_ext_operators(float)
6888  _cimg_create_ext_operators(double)
6889  _cimg_create_ext_operators(long double)
6890 
6891  template<typename T>
6892  inline CImg<_cimg_Tfloat> operator+(const char *const expression, const CImg<T>& img) {
6893  return img + expression;
6894  }
6895 
6896  template<typename T>
6897  inline CImg<_cimg_Tfloat> operator-(const char *const expression, const CImg<T>& img) {
6898  return CImg<_cimg_Tfloat>(img,false).fill(expression,true)-=img;
6899  }
6900 
6901  template<typename T>
6902  inline CImg<_cimg_Tfloat> operator*(const char *const expression, const CImg<T>& img) {
6903  return img*expression;
6904  }
6905 
6906  template<typename T>
6907  inline CImg<_cimg_Tfloat> operator/(const char *const expression, const CImg<T>& img) {
6908  return expression*img.get_invert();
6909  }
6910 
6911  template<typename T>
6912  inline CImg<T> operator&(const char *const expression, const CImg<T>& img) {
6913  return img & expression;
6914  }
6915 
6916  template<typename T>
6917  inline CImg<T> operator|(const char *const expression, const CImg<T>& img) {
6918  return img | expression;
6919  }
6920 
6921  template<typename T>
6922  inline CImg<T> operator^(const char *const expression, const CImg<T>& img) {
6923  return img ^ expression;
6924  }
6925 
6926  template<typename T>
6927  inline bool operator==(const char *const expression, const CImg<T>& img) {
6928  return img==expression;
6929  }
6930 
6931  template<typename T>
6932  inline bool operator!=(const char *const expression, const CImg<T>& img) {
6933  return img!=expression;
6934  }
6935 
6936  template<typename T>
6937  inline CImg<_cimg_Tfloat> sqr(const CImg<T>& instance) {
6938  return instance.get_sqr();
6939  }
6940 
6941  template<typename T>
6942  inline CImg<_cimg_Tfloat> sqrt(const CImg<T>& instance) {
6943  return instance.get_sqrt();
6944  }
6945 
6946  template<typename T>
6947  inline CImg<_cimg_Tfloat> exp(const CImg<T>& instance) {
6948  return instance.get_exp();
6949  }
6950 
6951  template<typename T>
6952  inline CImg<_cimg_Tfloat> log(const CImg<T>& instance) {
6953  return instance.get_log();
6954  }
6955 
6956  template<typename T>
6957  inline CImg<_cimg_Tfloat> log2(const CImg<T>& instance) {
6958  return instance.get_log2();
6959  }
6960 
6961  template<typename T>
6962  inline CImg<_cimg_Tfloat> log10(const CImg<T>& instance) {
6963  return instance.get_log10();
6964  }
6965 
6966  template<typename T>
6967  inline CImg<_cimg_Tfloat> abs(const CImg<T>& instance) {
6968  return instance.get_abs();
6969  }
6970 
6971  template<typename T>
6972  inline CImg<_cimg_Tfloat> sign(const CImg<T>& instance) {
6973  return instance.get_sign();
6974  }
6975 
6976  template<typename T>
6977  inline CImg<_cimg_Tfloat> cos(const CImg<T>& instance) {
6978  return instance.get_cos();
6979  }
6980 
6981  template<typename T>
6982  inline CImg<_cimg_Tfloat> sin(const CImg<T>& instance) {
6983  return instance.get_sin();
6984  }
6985 
6986  template<typename T>
6987  inline CImg<_cimg_Tfloat> sinc(const CImg<T>& instance) {
6988  return instance.get_sinc();
6989  }
6990 
6991  template<typename T>
6992  inline CImg<_cimg_Tfloat> tan(const CImg<T>& instance) {
6993  return instance.get_tan();
6994  }
6995 
6996  template<typename T>
6997  inline CImg<_cimg_Tfloat> acos(const CImg<T>& instance) {
6998  return instance.get_acos();
6999  }
7000 
7001  template<typename T>
7002  inline CImg<_cimg_Tfloat> asin(const CImg<T>& instance) {
7003  return instance.get_asin();
7004  }
7005 
7006  template<typename T>
7007  inline CImg<_cimg_Tfloat> atan(const CImg<T>& instance) {
7008  return instance.get_atan();
7009  }
7010 
7011  template<typename T>
7012  inline CImg<_cimg_Tfloat> cosh(const CImg<T>& instance) {
7013  return instance.get_cosh();
7014  }
7015 
7016  template<typename T>
7017  inline CImg<_cimg_Tfloat> sinh(const CImg<T>& instance) {
7018  return instance.get_sinh();
7019  }
7020 
7021  template<typename T>
7022  inline CImg<_cimg_Tfloat> tanh(const CImg<T>& instance) {
7023  return instance.get_tanh();
7024  }
7025 
7026  template<typename T>
7027  inline CImg<T> transpose(const CImg<T>& instance) {
7028  return instance.get_transpose();
7029  }
7030 
7031  template<typename T>
7032  inline CImg<_cimg_Tfloat> invert(const CImg<T>& instance) {
7033  return instance.get_invert();
7034  }
7035 
7036  template<typename T>
7037  inline CImg<_cimg_Tfloat> pseudoinvert(const CImg<T>& instance) {
7038  return instance.get_pseudoinvert();
7039  }
7040 
7041  /*-----------------------------------
7042  #
7043  # Define the CImgDisplay structure
7044  #
7045  ----------------------------------*/
7047 
7063  struct CImgDisplay {
7064  cimg_ulong _timer, _fps_frames, _fps_timer;
7065  unsigned int _width, _height, _normalization;
7066  float _fps_fps, _min, _max;
7067  bool _is_fullscreen;
7068  char *_title;
7069  unsigned int _window_width, _window_height, _button, *_keys, *_released_keys;
7070  int _window_x, _window_y, _mouse_x, _mouse_y, _wheel;
7071  bool _is_closed, _is_resized, _is_moved, _is_event,
7072  _is_keyESC, _is_keyF1, _is_keyF2, _is_keyF3, _is_keyF4, _is_keyF5, _is_keyF6, _is_keyF7,
7073  _is_keyF8, _is_keyF9, _is_keyF10, _is_keyF11, _is_keyF12, _is_keyPAUSE, _is_key1, _is_key2,
7074  _is_key3, _is_key4, _is_key5, _is_key6, _is_key7, _is_key8, _is_key9, _is_key0,
7075  _is_keyBACKSPACE, _is_keyINSERT, _is_keyHOME, _is_keyPAGEUP, _is_keyTAB, _is_keyQ, _is_keyW, _is_keyE,
7076  _is_keyR, _is_keyT, _is_keyY, _is_keyU, _is_keyI, _is_keyO, _is_keyP, _is_keyDELETE,
7077  _is_keyEND, _is_keyPAGEDOWN, _is_keyCAPSLOCK, _is_keyA, _is_keyS, _is_keyD, _is_keyF, _is_keyG,
7078  _is_keyH, _is_keyJ, _is_keyK, _is_keyL, _is_keyENTER, _is_keySHIFTLEFT, _is_keyZ, _is_keyX,
7079  _is_keyC, _is_keyV, _is_keyB, _is_keyN, _is_keyM, _is_keySHIFTRIGHT, _is_keyARROWUP, _is_keyCTRLLEFT,
7080  _is_keyAPPLEFT, _is_keyALT, _is_keySPACE, _is_keyALTGR, _is_keyAPPRIGHT, _is_keyMENU, _is_keyCTRLRIGHT,
7081  _is_keyARROWLEFT, _is_keyARROWDOWN, _is_keyARROWRIGHT, _is_keyPAD0, _is_keyPAD1, _is_keyPAD2, _is_keyPAD3,
7082  _is_keyPAD4, _is_keyPAD5, _is_keyPAD6, _is_keyPAD7, _is_keyPAD8, _is_keyPAD9, _is_keyPADADD, _is_keyPADSUB,
7083  _is_keyPADMUL, _is_keyPADDIV;
7084 
7086  //---------------------------
7087  //
7089 
7090  //---------------------------
7091 
7092 #ifdef cimgdisplay_plugin
7093 #include cimgdisplay_plugin
7094 #endif
7095 #ifdef cimgdisplay_plugin1
7096 #include cimgdisplay_plugin1
7097 #endif
7098 #ifdef cimgdisplay_plugin2
7099 #include cimgdisplay_plugin2
7100 #endif
7101 #ifdef cimgdisplay_plugin3
7102 #include cimgdisplay_plugin3
7103 #endif
7104 #ifdef cimgdisplay_plugin4
7105 #include cimgdisplay_plugin4
7106 #endif
7107 #ifdef cimgdisplay_plugin5
7108 #include cimgdisplay_plugin5
7109 #endif
7110 #ifdef cimgdisplay_plugin6
7111 #include cimgdisplay_plugin6
7112 #endif
7113 #ifdef cimgdisplay_plugin7
7114 #include cimgdisplay_plugin7
7115 #endif
7116 #ifdef cimgdisplay_plugin8
7117 #include cimgdisplay_plugin8
7118 #endif
7119 
7121  //--------------------------------------------------------
7122  //
7124 
7125  //--------------------------------------------------------
7126 
7128 
7132  assign();
7133  delete[] _keys;
7134  delete[] _released_keys;
7135  }
7136 
7138 
7149  _width(0),_height(0),_normalization(0),
7150  _min(0),_max(0),
7151  _is_fullscreen(false),
7152  _title(0),
7153  _window_width(0),_window_height(0),_button(0),
7154  _keys(new unsigned int[128]),_released_keys(new unsigned int[128]),
7155  _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0),
7156  _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) {
7157  assign();
7158  }
7159 
7161 
7170  CImgDisplay(const unsigned int width, const unsigned int height,
7171  const char *const title=0, const unsigned int normalization=3,
7172  const bool is_fullscreen=false, const bool is_closed=false):
7173  _width(0),_height(0),_normalization(0),
7174  _min(0),_max(0),
7175  _is_fullscreen(false),
7176  _title(0),
7177  _window_width(0),_window_height(0),_button(0),
7178  _keys(new unsigned int[128]),_released_keys(new unsigned int[128]),
7179  _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0),
7180  _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) {
7181  assign(width,height,title,normalization,is_fullscreen,is_closed);
7182  }
7183 
7185 
7193  template<typename T>
7194  explicit CImgDisplay(const CImg<T>& img,
7195  const char *const title=0, const unsigned int normalization=3,
7196  const bool is_fullscreen=false, const bool is_closed=false):
7197  _width(0),_height(0),_normalization(0),
7198  _min(0),_max(0),
7199  _is_fullscreen(false),
7200  _title(0),
7201  _window_width(0),_window_height(0),_button(0),
7202  _keys(new unsigned int[128]),_released_keys(new unsigned int[128]),
7203  _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0),
7204  _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) {
7205  assign(img,title,normalization,is_fullscreen,is_closed);
7206  }
7207 
7209 
7217  template<typename T>
7218  explicit CImgDisplay(const CImgList<T>& list,
7219  const char *const title=0, const unsigned int normalization=3,
7220  const bool is_fullscreen=false, const bool is_closed=false):
7221  _width(0),_height(0),_normalization(0),
7222  _min(0),_max(0),
7223  _is_fullscreen(false),
7224  _title(0),
7225  _window_width(0),_window_height(0),_button(0),
7226  _keys(new unsigned int[128]),_released_keys(new unsigned int[128]),
7227  _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0),
7228  _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) {
7229  assign(list,title,normalization,is_fullscreen,is_closed);
7230  }
7231 
7233 
7237  CImgDisplay(const CImgDisplay& disp):
7238  _width(0),_height(0),_normalization(0),
7239  _min(0),_max(0),
7240  _is_fullscreen(false),
7241  _title(0),
7242  _window_width(0),_window_height(0),_button(0),
7243  _keys(new unsigned int[128]),_released_keys(new unsigned int[128]),
7244  _window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0),
7245  _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) {
7246  assign(disp);
7247  }
7248 
7250 
7253  template<typename T>
7254  static void screenshot(CImg<T>& img) {
7255  return screenshot(0,0,cimg::type<int>::max(),cimg::type<int>::max(),img);
7256  }
7257 
7258 #if cimg_display==0
7259 
7260  static void _no_display_exception() {
7261  throw CImgDisplayException("CImgDisplay(): No display available.");
7262  }
7263 
7265 
7269  return flush();
7270  }
7271 
7273 
7275  CImgDisplay& assign(const unsigned int width, const unsigned int height,
7276  const char *const title=0, const unsigned int normalization=3,
7277  const bool is_fullscreen=false, const bool is_closed=false) {
7278  cimg::unused(width,height,title,normalization,is_fullscreen,is_closed);
7279  _no_display_exception();
7280  return assign();
7281  }
7282 
7284 
7286  template<typename T>
7288  const char *const title=0, const unsigned int normalization=3,
7289  const bool is_fullscreen=false, const bool is_closed=false) {
7290  _no_display_exception();
7291  return assign(img._width,img._height,title,normalization,is_fullscreen,is_closed);
7292  }
7293 
7295 
7297  template<typename T>
7299  const char *const title=0, const unsigned int normalization=3,
7300  const bool is_fullscreen=false, const bool is_closed=false) {
7301  _no_display_exception();
7302  return assign(list._width,list._width,title,normalization,is_fullscreen,is_closed);
7303  }
7304 
7306 
7309  _no_display_exception();
7310  return assign(disp._width,disp._height);
7311  }
7312 
7313 #endif
7314 
7316 
7324  static CImgDisplay& empty() {
7325  static CImgDisplay _empty;
7326  return _empty.assign();
7327  }
7328 
7330  static const CImgDisplay& const_empty() {
7331  static const CImgDisplay _empty;
7332  return _empty;
7333  }
7334 
7335 #define cimg_fitscreen(dx,dy,dz) CImgDisplay::_fitscreen(dx,dy,dz,128,-85,false), \
7336  CImgDisplay::_fitscreen(dx,dy,dz,128,-85,true)
7337  static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy, const unsigned int dz,
7338  const int dmin, const int dmax,const bool return_y) {
7339  const unsigned int _nw = dx + (dz>1?dz:0), _nh = dy + (dz>1?dz:0);
7340  unsigned int nw = _nw?_nw:1, nh = _nh?_nh:1;
7341  const unsigned int
7342  sw = (unsigned int)CImgDisplay::screen_width(),
7343  sh = (unsigned int)CImgDisplay::screen_height(),
7344  mw = dmin<0?(unsigned int)(sw*-dmin/100):(unsigned int)dmin,
7345  mh = dmin<0?(unsigned int)(sh*-dmin/100):(unsigned int)dmin,
7346  Mw = dmax<0?(unsigned int)(sw*-dmax/100):(unsigned int)dmax,
7347  Mh = dmax<0?(unsigned int)(sh*-dmax/100):(unsigned int)dmax;
7348  if (nw<mw) { nh = nh*mw/nw; nh+=(nh==0); nw = mw; }
7349  if (nh<mh) { nw = nw*mh/nh; nw+=(nw==0); nh = mh; }
7350  if (nw>Mw) { nh = nh*Mw/nw; nh+=(nh==0); nw = Mw; }
7351  if (nh>Mh) { nw = nw*Mh/nh; nw+=(nw==0); nh = Mh; }
7352  if (nw<mw) nw = mw;
7353  if (nh<mh) nh = mh;
7354  return return_y?nh:nw;
7355  }
7356 
7358  //------------------------------------------
7359  //
7361 
7362  //------------------------------------------
7363 
7365 
7368  template<typename t>
7370  return display(img);
7371  }
7372 
7374 
7377  template<typename t>
7379  return display(list);
7380  }
7381 
7383 
7387  return assign(disp);
7388  }
7389 
7391 
7394  operator bool() const {
7395  return !is_empty();
7396  }
7397 
7399  //------------------------------------------
7400  //
7402 
7403  //------------------------------------------
7404 
7406 
7408  bool is_empty() const {
7409  return !(_width && _height);
7410  }
7411 
7413 
7418  bool is_closed() const {
7419  return _is_closed;
7420  }
7421 
7423 
7425  bool is_resized() const {
7426  return _is_resized;
7427  }
7428 
7430 
7432  bool is_moved() const {
7433  return _is_moved;
7434  }
7435 
7437 
7439  bool is_event() const {
7440  return _is_event;
7441  }
7442 
7444 
7446  bool is_fullscreen() const {
7447  return _is_fullscreen;
7448  }
7449 
7451 
7454  bool is_key() const {
7455  return _is_keyESC || _is_keyF1 || _is_keyF2 || _is_keyF3 ||
7456  _is_keyF4 || _is_keyF5 || _is_keyF6 || _is_keyF7 ||
7457  _is_keyF8 || _is_keyF9 || _is_keyF10 || _is_keyF11 ||
7458  _is_keyF12 || _is_keyPAUSE || _is_key1 || _is_key2 ||
7459  _is_key3 || _is_key4 || _is_key5 || _is_key6 ||
7460  _is_key7 || _is_key8 || _is_key9 || _is_key0 ||
7461  _is_keyBACKSPACE || _is_keyINSERT || _is_keyHOME ||
7462  _is_keyPAGEUP || _is_keyTAB || _is_keyQ || _is_keyW ||
7463  _is_keyE || _is_keyR || _is_keyT || _is_keyY ||
7464  _is_keyU || _is_keyI || _is_keyO || _is_keyP ||
7465  _is_keyDELETE || _is_keyEND || _is_keyPAGEDOWN ||
7466  _is_keyCAPSLOCK || _is_keyA || _is_keyS || _is_keyD ||
7467  _is_keyF || _is_keyG || _is_keyH || _is_keyJ ||
7468  _is_keyK || _is_keyL || _is_keyENTER ||
7469  _is_keySHIFTLEFT || _is_keyZ || _is_keyX || _is_keyC ||
7470  _is_keyV || _is_keyB || _is_keyN || _is_keyM ||
7471  _is_keySHIFTRIGHT || _is_keyARROWUP || _is_keyCTRLLEFT ||
7472  _is_keyAPPLEFT || _is_keyALT || _is_keySPACE || _is_keyALTGR ||
7473  _is_keyAPPRIGHT || _is_keyMENU || _is_keyCTRLRIGHT ||
7474  _is_keyARROWLEFT || _is_keyARROWDOWN || _is_keyARROWRIGHT ||
7475  _is_keyPAD0 || _is_keyPAD1 || _is_keyPAD2 ||
7476  _is_keyPAD3 || _is_keyPAD4 || _is_keyPAD5 ||
7477  _is_keyPAD6 || _is_keyPAD7 || _is_keyPAD8 ||
7478  _is_keyPAD9 || _is_keyPADADD || _is_keyPADSUB ||
7479  _is_keyPADMUL || _is_keyPADDIV;
7480  }
7481 
7483 
7496  bool is_key(const unsigned int keycode) const {
7497 #define _cimg_iskey_test(k) if (keycode==cimg::key##k) return _is_key##k;
7498  _cimg_iskey_test(ESC); _cimg_iskey_test(F1); _cimg_iskey_test(F2); _cimg_iskey_test(F3);
7499  _cimg_iskey_test(F4); _cimg_iskey_test(F5); _cimg_iskey_test(F6); _cimg_iskey_test(F7);
7500  _cimg_iskey_test(F8); _cimg_iskey_test(F9); _cimg_iskey_test(F10); _cimg_iskey_test(F11);
7501  _cimg_iskey_test(F12); _cimg_iskey_test(PAUSE); _cimg_iskey_test(1); _cimg_iskey_test(2);
7502  _cimg_iskey_test(3); _cimg_iskey_test(4); _cimg_iskey_test(5); _cimg_iskey_test(6);
7503  _cimg_iskey_test(7); _cimg_iskey_test(8); _cimg_iskey_test(9); _cimg_iskey_test(0);
7504  _cimg_iskey_test(BACKSPACE); _cimg_iskey_test(INSERT); _cimg_iskey_test(HOME);
7505  _cimg_iskey_test(PAGEUP); _cimg_iskey_test(TAB); _cimg_iskey_test(Q); _cimg_iskey_test(W);
7506  _cimg_iskey_test(E); _cimg_iskey_test(R); _cimg_iskey_test(T); _cimg_iskey_test(Y);
7507  _cimg_iskey_test(U); _cimg_iskey_test(I); _cimg_iskey_test(O); _cimg_iskey_test(P);
7508  _cimg_iskey_test(DELETE); _cimg_iskey_test(END); _cimg_iskey_test(PAGEDOWN);
7509  _cimg_iskey_test(CAPSLOCK); _cimg_iskey_test(A); _cimg_iskey_test(S); _cimg_iskey_test(D);
7510  _cimg_iskey_test(F); _cimg_iskey_test(G); _cimg_iskey_test(H); _cimg_iskey_test(J);
7511  _cimg_iskey_test(K); _cimg_iskey_test(L); _cimg_iskey_test(ENTER);
7512  _cimg_iskey_test(SHIFTLEFT); _cimg_iskey_test(Z); _cimg_iskey_test(X); _cimg_iskey_test(C);
7513  _cimg_iskey_test(V); _cimg_iskey_test(B); _cimg_iskey_test(N); _cimg_iskey_test(M);
7514  _cimg_iskey_test(SHIFTRIGHT); _cimg_iskey_test(ARROWUP); _cimg_iskey_test(CTRLLEFT);
7515  _cimg_iskey_test(APPLEFT); _cimg_iskey_test(ALT); _cimg_iskey_test(SPACE); _cimg_iskey_test(ALTGR);
7516  _cimg_iskey_test(APPRIGHT); _cimg_iskey_test(MENU); _cimg_iskey_test(CTRLRIGHT);
7517  _cimg_iskey_test(ARROWLEFT); _cimg_iskey_test(ARROWDOWN); _cimg_iskey_test(ARROWRIGHT);
7518  _cimg_iskey_test(PAD0); _cimg_iskey_test(PAD1); _cimg_iskey_test(PAD2);
7519  _cimg_iskey_test(PAD3); _cimg_iskey_test(PAD4); _cimg_iskey_test(PAD5);
7520  _cimg_iskey_test(PAD6); _cimg_iskey_test(PAD7); _cimg_iskey_test(PAD8);
7521  _cimg_iskey_test(PAD9); _cimg_iskey_test(PADADD); _cimg_iskey_test(PADSUB);
7522  _cimg_iskey_test(PADMUL); _cimg_iskey_test(PADDIV);
7523  return false;
7524  }
7525 
7527 
7540  bool& is_key(const char *const keycode) {
7541  static bool f = false;
7542  f = false;
7543 #define _cimg_iskey_test2(k) if (!cimg::strcasecmp(keycode,#k)) return _is_key##k;
7544  _cimg_iskey_test2(ESC); _cimg_iskey_test2(F1); _cimg_iskey_test2(F2); _cimg_iskey_test2(F3);
7545  _cimg_iskey_test2(F4); _cimg_iskey_test2(F5); _cimg_iskey_test2(F6); _cimg_iskey_test2(F7);
7546  _cimg_iskey_test2(F8); _cimg_iskey_test2(F9); _cimg_iskey_test2(F10); _cimg_iskey_test2(F11);
7547  _cimg_iskey_test2(F12); _cimg_iskey_test2(PAUSE); _cimg_iskey_test2(1); _cimg_iskey_test2(2);
7548  _cimg_iskey_test2(3); _cimg_iskey_test2(4); _cimg_iskey_test2(5); _cimg_iskey_test2(6);
7549  _cimg_iskey_test2(7); _cimg_iskey_test2(8); _cimg_iskey_test2(9); _cimg_iskey_test2(0);
7550  _cimg_iskey_test2(BACKSPACE); _cimg_iskey_test2(INSERT); _cimg_iskey_test2(HOME);
7551  _cimg_iskey_test2(PAGEUP); _cimg_iskey_test2(TAB); _cimg_iskey_test2(Q); _cimg_iskey_test2(W);
7552  _cimg_iskey_test2(E); _cimg_iskey_test2(R); _cimg_iskey_test2(T); _cimg_iskey_test2(Y);
7553  _cimg_iskey_test2(U); _cimg_iskey_test2(I); _cimg_iskey_test2(O); _cimg_iskey_test2(P);
7554  _cimg_iskey_test2(DELETE); _cimg_iskey_test2(END); _cimg_iskey_test2(PAGEDOWN);
7555  _cimg_iskey_test2(CAPSLOCK); _cimg_iskey_test2(A); _cimg_iskey_test2(S); _cimg_iskey_test2(D);
7556  _cimg_iskey_test2(F); _cimg_iskey_test2(G); _cimg_iskey_test2(H); _cimg_iskey_test2(J);
7557  _cimg_iskey_test2(K); _cimg_iskey_test2(L); _cimg_iskey_test2(ENTER);
7558  _cimg_iskey_test2(SHIFTLEFT); _cimg_iskey_test2(Z); _cimg_iskey_test2(X); _cimg_iskey_test2(C);
7559  _cimg_iskey_test2(V); _cimg_iskey_test2(B); _cimg_iskey_test2(N); _cimg_iskey_test2(M);
7560  _cimg_iskey_test2(SHIFTRIGHT); _cimg_iskey_test2(ARROWUP); _cimg_iskey_test2(CTRLLEFT);
7561  _cimg_iskey_test2(APPLEFT); _cimg_iskey_test2(ALT); _cimg_iskey_test2(SPACE); _cimg_iskey_test2(ALTGR);
7562  _cimg_iskey_test2(APPRIGHT); _cimg_iskey_test2(MENU); _cimg_iskey_test2(CTRLRIGHT);
7563  _cimg_iskey_test2(ARROWLEFT); _cimg_iskey_test2(ARROWDOWN); _cimg_iskey_test2(ARROWRIGHT);
7564  _cimg_iskey_test2(PAD0); _cimg_iskey_test2(PAD1); _cimg_iskey_test2(PAD2);
7565  _cimg_iskey_test2(PAD3); _cimg_iskey_test2(PAD4); _cimg_iskey_test2(PAD5);
7566  _cimg_iskey_test2(PAD6); _cimg_iskey_test2(PAD7); _cimg_iskey_test2(PAD8);
7567  _cimg_iskey_test2(PAD9); _cimg_iskey_test2(PADADD); _cimg_iskey_test2(PADSUB);
7568  _cimg_iskey_test2(PADMUL); _cimg_iskey_test2(PADDIV);
7569  return f;
7570  }
7571 
7573 
7589  bool is_key_sequence(const unsigned int *const keycodes_sequence, const unsigned int length,
7590  const bool remove_sequence=false) {
7591  if (keycodes_sequence && length) {
7592  const unsigned int
7593  *const ps_end = keycodes_sequence + length - 1,
7594  *const pk_end = (unsigned int*)_keys + 1 + 128 - length,
7595  k = *ps_end;
7596  for (unsigned int *pk = (unsigned int*)_keys; pk<pk_end; ) {
7597  if (*(pk++)==k) {
7598  bool res = true;
7599  const unsigned int *ps = ps_end, *pk2 = pk;
7600  for (unsigned int i = 1; i<length; ++i) res = (*(--ps)==*(pk2++));
7601  if (res) {
7602  if (remove_sequence) std::memset((void*)(pk - 1),0,sizeof(unsigned int)*length);
7603  return true;
7604  }
7605  }
7606  }
7607  }
7608  return false;
7609  }
7610 
7611 #define _cimg_iskey_def(k) \
7612  bool is_key##k() const { \
7613  return _is_key##k; \
7614  }
7615 
7617 
7620  _cimg_iskey_def(ESC); _cimg_iskey_def(F1); _cimg_iskey_def(F2); _cimg_iskey_def(F3);
7621  _cimg_iskey_def(F4); _cimg_iskey_def(F5); _cimg_iskey_def(F6); _cimg_iskey_def(F7);
7622  _cimg_iskey_def(F8); _cimg_iskey_def(F9); _cimg_iskey_def(F10); _cimg_iskey_def(F11);
7623  _cimg_iskey_def(F12); _cimg_iskey_def(PAUSE); _cimg_iskey_def(1); _cimg_iskey_def(2);
7624  _cimg_iskey_def(3); _cimg_iskey_def(4); _cimg_iskey_def(5); _cimg_iskey_def(6);
7625  _cimg_iskey_def(7); _cimg_iskey_def(8); _cimg_iskey_def(9); _cimg_iskey_def(0);
7626  _cimg_iskey_def(BACKSPACE); _cimg_iskey_def(INSERT); _cimg_iskey_def(HOME);
7627  _cimg_iskey_def(PAGEUP); _cimg_iskey_def(TAB); _cimg_iskey_def(Q); _cimg_iskey_def(W);
7628  _cimg_iskey_def(E); _cimg_iskey_def(R); _cimg_iskey_def(T); _cimg_iskey_def(Y);
7629  _cimg_iskey_def(U); _cimg_iskey_def(I); _cimg_iskey_def(O); _cimg_iskey_def(P);
7630  _cimg_iskey_def(DELETE); _cimg_iskey_def(END); _cimg_iskey_def(PAGEDOWN);
7631  _cimg_iskey_def(CAPSLOCK); _cimg_iskey_def(A); _cimg_iskey_def(S); _cimg_iskey_def(D);
7632  _cimg_iskey_def(F); _cimg_iskey_def(G); _cimg_iskey_def(H); _cimg_iskey_def(J);
7633  _cimg_iskey_def(K); _cimg_iskey_def(L); _cimg_iskey_def(ENTER);
7634  _cimg_iskey_def(SHIFTLEFT); _cimg_iskey_def(Z); _cimg_iskey_def(X); _cimg_iskey_def(C);
7635  _cimg_iskey_def(V); _cimg_iskey_def(B); _cimg_iskey_def(N); _cimg_iskey_def(M);
7636  _cimg_iskey_def(SHIFTRIGHT); _cimg_iskey_def(ARROWUP); _cimg_iskey_def(CTRLLEFT);
7637  _cimg_iskey_def(APPLEFT); _cimg_iskey_def(ALT); _cimg_iskey_def(SPACE); _cimg_iskey_def(ALTGR);
7638  _cimg_iskey_def(APPRIGHT); _cimg_iskey_def(MENU); _cimg_iskey_def(CTRLRIGHT);
7639  _cimg_iskey_def(ARROWLEFT); _cimg_iskey_def(ARROWDOWN); _cimg_iskey_def(ARROWRIGHT);
7640  _cimg_iskey_def(PAD0); _cimg_iskey_def(PAD1); _cimg_iskey_def(PAD2);
7641  _cimg_iskey_def(PAD3); _cimg_iskey_def(PAD4); _cimg_iskey_def(PAD5);
7642  _cimg_iskey_def(PAD6); _cimg_iskey_def(PAD7); _cimg_iskey_def(PAD8);
7643  _cimg_iskey_def(PAD9); _cimg_iskey_def(PADADD); _cimg_iskey_def(PADSUB);
7644  _cimg_iskey_def(PADMUL); _cimg_iskey_def(PADDIV);
7645 
7647  //------------------------------------------
7648  //
7650 
7651  //------------------------------------------
7652 
7653 #if cimg_display==0
7654 
7656 
7658  static int screen_width() {
7659  _no_display_exception();
7660  return 0;
7661  }
7662 
7664 
7666  static int screen_height() {
7667  _no_display_exception();
7668  return 0;
7669  }
7670 
7671 #endif
7672 
7674 
7678  int width() const {
7679  return (int)_width;
7680  }
7681 
7683 
7687  int height() const {
7688  return (int)_height;
7689  }
7690 
7692 
7714  unsigned int normalization() const {
7715  return _normalization;
7716  }
7717 
7719 
7723  const char *title() const {
7724  return _title?_title:"";
7725  }
7726 
7728 
7732  int window_width() const {
7733  return (int)_window_width;
7734  }
7735 
7737 
7741  int window_height() const {
7742  return (int)_window_height;
7743  }
7744 
7746 
7749  int window_x() const {
7750  return _window_x;
7751  }
7752 
7754 
7757  int window_y() const {
7758  return _window_y;
7759  }
7760 
7762 
7767  int mouse_x() const {
7768  return _mouse_x;
7769  }
7770 
7772 
7777  int mouse_y() const {
7778  return _mouse_y;
7779  }
7780 
7782 
7807  unsigned int button() const {
7808  return _button;
7809  }
7810 
7812 
7836  int wheel() const {
7837  return _wheel;
7838  }
7839 
7841 
7853  unsigned int key(const unsigned int pos=0) const {
7854  return pos<128?_keys[pos]:0;
7855  }
7856 
7858 
7870  unsigned int released_key(const unsigned int pos=0) const {
7871  return pos<128?_released_keys[pos]:0;
7872  }
7873 
7875 
7883  static unsigned int keycode(const char *const keycode) {
7884 #define _cimg_keycode(k) if (!cimg::strcasecmp(keycode,#k)) return cimg::key##k;
7885  _cimg_keycode(ESC); _cimg_keycode(F1); _cimg_keycode(F2); _cimg_keycode(F3);
7886  _cimg_keycode(F4); _cimg_keycode(F5); _cimg_keycode(F6); _cimg_keycode(F7);
7887  _cimg_keycode(F8); _cimg_keycode(F9); _cimg_keycode(F10); _cimg_keycode(F11);
7888  _cimg_keycode(F12); _cimg_keycode(PAUSE); _cimg_keycode(1); _cimg_keycode(2);
7889  _cimg_keycode(3); _cimg_keycode(4); _cimg_keycode(5); _cimg_keycode(6);
7890  _cimg_keycode(7); _cimg_keycode(8); _cimg_keycode(9); _cimg_keycode(0);
7891  _cimg_keycode(BACKSPACE); _cimg_keycode(INSERT); _cimg_keycode(HOME);
7892  _cimg_keycode(PAGEUP); _cimg_keycode(TAB); _cimg_keycode(Q); _cimg_keycode(W);
7893  _cimg_keycode(E); _cimg_keycode(R); _cimg_keycode(T); _cimg_keycode(Y);
7894  _cimg_keycode(U); _cimg_keycode(I); _cimg_keycode(O); _cimg_keycode(P);
7895  _cimg_keycode(DELETE); _cimg_keycode(END); _cimg_keycode(PAGEDOWN);
7896  _cimg_keycode(CAPSLOCK); _cimg_keycode(A); _cimg_keycode(S); _cimg_keycode(D);
7897  _cimg_keycode(F); _cimg_keycode(G); _cimg_keycode(H); _cimg_keycode(J);
7898  _cimg_keycode(K); _cimg_keycode(L); _cimg_keycode(ENTER);
7899  _cimg_keycode(SHIFTLEFT); _cimg_keycode(Z); _cimg_keycode(X); _cimg_keycode(C);
7900  _cimg_keycode(V); _cimg_keycode(B); _cimg_keycode(N); _cimg_keycode(M);
7901  _cimg_keycode(SHIFTRIGHT); _cimg_keycode(ARROWUP); _cimg_keycode(CTRLLEFT);
7902  _cimg_keycode(APPLEFT); _cimg_keycode(ALT); _cimg_keycode(SPACE); _cimg_keycode(ALTGR);
7903  _cimg_keycode(APPRIGHT); _cimg_keycode(MENU); _cimg_keycode(CTRLRIGHT);
7904  _cimg_keycode(ARROWLEFT); _cimg_keycode(ARROWDOWN); _cimg_keycode(ARROWRIGHT);
7905  _cimg_keycode(PAD0); _cimg_keycode(PAD1); _cimg_keycode(PAD2);
7906  _cimg_keycode(PAD3); _cimg_keycode(PAD4); _cimg_keycode(PAD5);
7907  _cimg_keycode(PAD6); _cimg_keycode(PAD7); _cimg_keycode(PAD8);
7908  _cimg_keycode(PAD9); _cimg_keycode(PADADD); _cimg_keycode(PADSUB);
7909  _cimg_keycode(PADMUL); _cimg_keycode(PADDIV);
7910  return 0;
7911  }
7912 
7914 
7919  if (!_fps_timer) _fps_timer = cimg::time();
7920  const float delta = (cimg::time() - _fps_timer)/1000.0f;
7921  ++_fps_frames;
7922  if (delta>=1) {
7923  _fps_fps = _fps_frames/delta;
7924  _fps_frames = 0;
7925  _fps_timer = cimg::time();
7926  }
7927  return _fps_fps;
7928  }
7929 
7931  //---------------------------------------
7932  //
7934 
7935  //---------------------------------------
7936 
7937 #if cimg_display==0
7938 
7940 
7944  template<typename T>
7945  CImgDisplay& display(const CImg<T>& img) {
7946  return assign(img);
7947  }
7948 
7949 #endif
7950 
7952 
7959  template<typename T>
7960  CImgDisplay& display(const CImgList<T>& list, const char axis='x', const float align=0) {
7961  if (list._width==1) {
7962  const CImg<T>& img = list[0];
7963  if (img._depth==1 && (img._spectrum==1 || img._spectrum>=3) && _normalization!=1) return display(img);
7964  }
7965  CImgList<typename CImg<T>::ucharT> visu(list._width);
7966  unsigned int dims = 0;
7967  cimglist_for(list,l) {
7968  const CImg<T>& img = list._data[l];
7969  img.__get_select(*this,_normalization,(img._width - 1)/2,(img._height - 1)/2,
7970  (img._depth - 1)/2).move_to(visu[l]);
7971  dims = std::max(dims,visu[l]._spectrum);
7972  }
7973  cimglist_for(list,l) if (visu[l]._spectrum<dims) visu[l].resize(-100,-100,-100,dims,1);
7974  visu.get_append(axis,align).display(*this);
7975  return *this;
7976  }
7977 
7978 #if cimg_display==0
7979 
7981 
7987  return assign();
7988  }
7989 
7991 
7999  return assign();
8000  }
8001 
8003 
8009  CImgDisplay& move(const int pos_x, const int pos_y) {
8010  return assign(pos_x,pos_y);
8011  }
8012 
8013 #endif
8014 
8016 
8023  CImgDisplay& resize(const bool force_redraw=true) {
8024  resize(window_width(),window_height(),force_redraw);
8025  return *this;
8026  }
8027 
8028 #if cimg_display==0
8029 
8031 
8037  CImgDisplay& resize(const int width, const int height, const bool force_redraw=true) {
8038  return assign(width,height,0,3,force_redraw);
8039  }
8040 
8041 #endif
8042 
8044 
8052  template<typename T>
8053  CImgDisplay& resize(const CImg<T>& img, const bool force_redraw=true) {
8054  return resize(img._width,img._height,force_redraw);
8055  }
8056 
8058 
8066  CImgDisplay& resize(const CImgDisplay& disp, const bool force_redraw=true) {
8067  return resize(disp.width(),disp.height(),force_redraw);
8068  }
8069 
8070  // [internal] Render pixel buffer with size (wd,hd) from source buffer of size (ws,hs).
8071  template<typename t, typename T>
8072  static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs,
8073  t *ptrd, const unsigned int wd, const unsigned int hd) {
8074  unsigned int *const offx = new unsigned int[wd], *const offy = new unsigned int[hd + 1], *poffx, *poffy;
8075  float s, curr, old;
8076  s = (float)ws/wd;
8077  poffx = offx; curr = 0; for (unsigned int x = 0; x<wd; ++x) {
8078  old = curr; curr+=s; *(poffx++) = (unsigned int)curr - (unsigned int)old;
8079  }
8080  s = (float)hs/hd;
8081  poffy = offy; curr = 0; for (unsigned int y = 0; y<hd; ++y) {
8082  old = curr; curr+=s; *(poffy++) = ws*((unsigned int)curr - (unsigned int)old);
8083  }
8084  *poffy = 0;
8085  poffy = offy;
8086  for (unsigned int y = 0; y<hd; ) {
8087  const T *ptr = ptrs;
8088  poffx = offx;
8089  for (unsigned int x = 0; x<wd; ++x) { *(ptrd++) = *ptr; ptr+=*(poffx++); }
8090  ++y;
8091  unsigned int dy = *(poffy++);
8092  for ( ; !dy && y<hd; std::memcpy(ptrd,ptrd - wd,sizeof(t)*wd), ++y, ptrd+=wd, dy = *(poffy++)) {}
8093  ptrs+=dy;
8094  }
8095  delete[] offx; delete[] offy;
8096  }
8097 
8099 
8102  CImgDisplay& set_normalization(const unsigned int normalization) {
8103  _normalization = normalization;
8104  _min = _max = 0;
8105  return *this;
8106  }
8107 
8108 #if cimg_display==0
8109 
8111 
8123  CImgDisplay& set_title(const char *const format, ...) {
8124  return assign(0,0,format);
8125  }
8126 
8127 #endif
8128 
8130 
8141  CImgDisplay& set_fullscreen(const bool is_fullscreen, const bool force_redraw=true) {
8142  if (is_empty() || _is_fullscreen==is_fullscreen) return *this;
8143  return toggle_fullscreen(force_redraw);
8144  }
8145 
8146 #if cimg_display==0
8147 
8149 
8153  CImgDisplay& toggle_fullscreen(const bool force_redraw=true) {
8154  return assign(_width,_height,0,3,force_redraw);
8155  }
8156 
8158 
8163  return assign();
8164  }
8165 
8167 
8172  return assign();
8173  }
8174 
8176 
8180  CImgDisplay& set_mouse(const int pos_x, const int pos_y) {
8181  return assign(pos_x,pos_y);
8182  }
8183 
8184 #endif
8185 
8187 
8191  _button = 0;
8192  _is_event = true;
8193 #if cimg_display==1
8194  pthread_cond_broadcast(&cimg::X11_attr().wait_event);
8195 #elif cimg_display==2
8196  SetEvent(cimg::Win32_attr().wait_event);
8197 #endif
8198  return *this;
8199  }
8200 
8202 
8206  CImgDisplay& set_button(const unsigned int button, const bool is_pressed=true) {
8207  const unsigned int buttoncode = button==1U?1U:button==2U?2U:button==3U?4U:0U;
8208  if (is_pressed) _button |= buttoncode; else _button &= ~buttoncode;
8209  _is_event = buttoncode?true:false;
8210  if (buttoncode) {
8211 #if cimg_display==1
8212  pthread_cond_broadcast(&cimg::X11_attr().wait_event);
8213 #elif cimg_display==2
8214  SetEvent(cimg::Win32_attr().wait_event);
8215 #endif
8216  }
8217  return *this;
8218  }
8219 
8221 
8225  _wheel = 0;
8226  _is_event = true;
8227 #if cimg_display==1
8228  pthread_cond_broadcast(&cimg::X11_attr().wait_event);
8229 #elif cimg_display==2
8230  SetEvent(cimg::Win32_attr().wait_event);
8231 #endif
8232  return *this;
8233  }
8234 
8236 
8240  CImgDisplay& set_wheel(const int amplitude) {
8241  _wheel+=amplitude;
8242  _is_event = amplitude?true:false;
8243  if (amplitude) {
8244 #if cimg_display==1
8245  pthread_cond_broadcast(&cimg::X11_attr().wait_event);
8246 #elif cimg_display==2
8247  SetEvent(cimg::Win32_attr().wait_event);
8248 #endif
8249  }
8250  return *this;
8251  }
8252 
8254 
8258  std::memset((void*)_keys,0,128*sizeof(unsigned int));
8259  std::memset((void*)_released_keys,0,128*sizeof(unsigned int));
8260  _is_keyESC = _is_keyF1 = _is_keyF2 = _is_keyF3 = _is_keyF4 = _is_keyF5 = _is_keyF6 = _is_keyF7 = _is_keyF8 =
8261  _is_keyF9 = _is_keyF10 = _is_keyF11 = _is_keyF12 = _is_keyPAUSE = _is_key1 = _is_key2 = _is_key3 = _is_key4 =
8262  _is_key5 = _is_key6 = _is_key7 = _is_key8 = _is_key9 = _is_key0 = _is_keyBACKSPACE = _is_keyINSERT =
8263  _is_keyHOME = _is_keyPAGEUP = _is_keyTAB = _is_keyQ = _is_keyW = _is_keyE = _is_keyR = _is_keyT = _is_keyY =
8264  _is_keyU = _is_keyI = _is_keyO = _is_keyP = _is_keyDELETE = _is_keyEND = _is_keyPAGEDOWN = _is_keyCAPSLOCK =
8265  _is_keyA = _is_keyS = _is_keyD = _is_keyF = _is_keyG = _is_keyH = _is_keyJ = _is_keyK = _is_keyL =
8266  _is_keyENTER = _is_keySHIFTLEFT = _is_keyZ = _is_keyX = _is_keyC = _is_keyV = _is_keyB = _is_keyN =
8267  _is_keyM = _is_keySHIFTRIGHT = _is_keyARROWUP = _is_keyCTRLLEFT = _is_keyAPPLEFT = _is_keyALT = _is_keySPACE =
8268  _is_keyALTGR = _is_keyAPPRIGHT = _is_keyMENU = _is_keyCTRLRIGHT = _is_keyARROWLEFT = _is_keyARROWDOWN =
8269  _is_keyARROWRIGHT = _is_keyPAD0 = _is_keyPAD1 = _is_keyPAD2 = _is_keyPAD3 = _is_keyPAD4 = _is_keyPAD5 =
8270  _is_keyPAD6 = _is_keyPAD7 = _is_keyPAD8 = _is_keyPAD9 = _is_keyPADADD = _is_keyPADSUB = _is_keyPADMUL =
8271  _is_keyPADDIV = false;
8272  _is_event = true;
8273 #if cimg_display==1
8274  pthread_cond_broadcast(&cimg::X11_attr().wait_event);
8275 #elif cimg_display==2
8276  SetEvent(cimg::Win32_attr().wait_event);
8277 #endif
8278  return *this;
8279  }
8280 
8282 
8288  CImgDisplay& set_key(const unsigned int keycode, const bool is_pressed=true) {
8289 #define _cimg_set_key(k) if (keycode==cimg::key##k) _is_key##k = is_pressed;
8290  _cimg_set_key(ESC); _cimg_set_key(F1); _cimg_set_key(F2); _cimg_set_key(F3);
8291  _cimg_set_key(F4); _cimg_set_key(F5); _cimg_set_key(F6); _cimg_set_key(F7);
8292  _cimg_set_key(F8); _cimg_set_key(F9); _cimg_set_key(F10); _cimg_set_key(F11);
8293  _cimg_set_key(F12); _cimg_set_key(PAUSE); _cimg_set_key(1); _cimg_set_key(2);
8294  _cimg_set_key(3); _cimg_set_key(4); _cimg_set_key(5); _cimg_set_key(6);
8295  _cimg_set_key(7); _cimg_set_key(8); _cimg_set_key(9); _cimg_set_key(0);
8296  _cimg_set_key(BACKSPACE); _cimg_set_key(INSERT); _cimg_set_key(HOME);
8297  _cimg_set_key(PAGEUP); _cimg_set_key(TAB); _cimg_set_key(Q); _cimg_set_key(W);
8298  _cimg_set_key(E); _cimg_set_key(R); _cimg_set_key(T); _cimg_set_key(Y);
8299  _cimg_set_key(U); _cimg_set_key(I); _cimg_set_key(O); _cimg_set_key(P);
8300  _cimg_set_key(DELETE); _cimg_set_key(END); _cimg_set_key(PAGEDOWN);
8301  _cimg_set_key(CAPSLOCK); _cimg_set_key(A); _cimg_set_key(S); _cimg_set_key(D);
8302  _cimg_set_key(F); _cimg_set_key(G); _cimg_set_key(H); _cimg_set_key(J);
8303  _cimg_set_key(K); _cimg_set_key(L); _cimg_set_key(ENTER);
8304  _cimg_set_key(SHIFTLEFT); _cimg_set_key(Z); _cimg_set_key(X); _cimg_set_key(C);
8305  _cimg_set_key(V); _cimg_set_key(B); _cimg_set_key(N); _cimg_set_key(M);
8306  _cimg_set_key(SHIFTRIGHT); _cimg_set_key(ARROWUP); _cimg_set_key(CTRLLEFT);
8307  _cimg_set_key(APPLEFT); _cimg_set_key(ALT); _cimg_set_key(SPACE); _cimg_set_key(ALTGR);
8308  _cimg_set_key(APPRIGHT); _cimg_set_key(MENU); _cimg_set_key(CTRLRIGHT);
8309  _cimg_set_key(ARROWLEFT); _cimg_set_key(ARROWDOWN); _cimg_set_key(ARROWRIGHT);
8310  _cimg_set_key(PAD0); _cimg_set_key(PAD1); _cimg_set_key(PAD2);
8311  _cimg_set_key(PAD3); _cimg_set_key(PAD4); _cimg_set_key(PAD5);
8312  _cimg_set_key(PAD6); _cimg_set_key(PAD7); _cimg_set_key(PAD8);
8313  _cimg_set_key(PAD9); _cimg_set_key(PADADD); _cimg_set_key(PADSUB);
8314  _cimg_set_key(PADMUL); _cimg_set_key(PADDIV);
8315  if (is_pressed) {
8316  if (*_keys)
8317  std::memmove((void*)(_keys + 1),(void*)_keys,127*sizeof(unsigned int));
8318  *_keys = keycode;
8319  if (*_released_keys) {
8320  std::memmove((void*)(_released_keys + 1),(void*)_released_keys,127*sizeof(unsigned int));
8321  *_released_keys = 0;
8322  }
8323  } else {
8324  if (*_keys) {
8325  std::memmove((void*)(_keys + 1),(void*)_keys,127*sizeof(unsigned int));
8326  *_keys = 0;
8327  }
8328  if (*_released_keys)
8329  std::memmove((void*)(_released_keys + 1),(void*)_released_keys,127*sizeof(unsigned int));
8330  *_released_keys = keycode;
8331  }
8332  _is_event = keycode?true:false;
8333  if (keycode) {
8334 #if cimg_display==1
8335  pthread_cond_broadcast(&cimg::X11_attr().wait_event);
8336 #elif cimg_display==2
8337  SetEvent(cimg::Win32_attr().wait_event);
8338 #endif
8339  }
8340  return *this;
8341  }
8342 
8344 
8348  set_key().set_button().set_wheel();
8349  _is_resized = _is_moved = _is_event = false;
8350  _fps_timer = _fps_frames = _timer = 0;
8351  _fps_fps = 0;
8352  return *this;
8353  }
8354 
8357  wait(*this);
8358  return *this;
8359  }
8360 
8362 
8366  CImgDisplay& wait(const unsigned int milliseconds) {
8367  cimg::_wait(milliseconds,_timer);
8368  return *this;
8369  }
8370 
8372  static void wait(CImgDisplay& disp1) {
8373  disp1._is_event = false;
8374  while (!disp1._is_closed && !disp1._is_event) wait_all();
8375  }
8376 
8378  static void wait(CImgDisplay& disp1, CImgDisplay& disp2) {
8379  disp1._is_event = disp2._is_event = false;
8380  while ((!disp1._is_closed || !disp2._is_closed) &&
8381  !disp1._is_event && !disp2._is_event) wait_all();
8382  }
8383 
8385  static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3) {
8386  disp1._is_event = disp2._is_event = disp3._is_event = false;
8387  while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed) &&
8388  !disp1._is_event && !disp2._is_event && !disp3._is_event) wait_all();
8389  }
8390 
8392  static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4) {
8393  disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = false;
8394  while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed) &&
8395  !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event) wait_all();
8396  }
8397 
8399  static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4,
8400  CImgDisplay& disp5) {
8401  disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = false;
8402  while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed) &&
8403  !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event)
8404  wait_all();
8405  }
8406 
8408  static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5,
8409  CImgDisplay& disp6) {
8410  disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event =
8411  disp6._is_event = false;
8412  while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed ||
8413  !disp6._is_closed) &&
8414  !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event &&
8415  !disp6._is_event) wait_all();
8416  }
8417 
8419  static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5,
8420  CImgDisplay& disp6, CImgDisplay& disp7) {
8421  disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event =
8422  disp6._is_event = disp7._is_event = false;
8423  while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed ||
8424  !disp6._is_closed || !disp7._is_closed) &&
8425  !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event &&
8426  !disp6._is_event && !disp7._is_event) wait_all();
8427  }
8428 
8430  static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5,
8431  CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8) {
8432  disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event =
8433  disp6._is_event = disp7._is_event = disp8._is_event = false;
8434  while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed ||
8435  !disp6._is_closed || !disp7._is_closed || !disp8._is_closed) &&
8436  !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event &&
8437  !disp6._is_event && !disp7._is_event && !disp8._is_event) wait_all();
8438  }
8439 
8441  static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5,
8442  CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8, CImgDisplay& disp9) {
8443  disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event =
8444  disp6._is_event = disp7._is_event = disp8._is_event = disp9._is_event = false;
8445  while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed ||
8446  !disp6._is_closed || !disp7._is_closed || !disp8._is_closed || !disp9._is_closed) &&
8447  !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event &&
8448  !disp6._is_event && !disp7._is_event && !disp8._is_event && !disp9._is_event) wait_all();
8449  }
8450 
8452  static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5,
8453  CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8, CImgDisplay& disp9,
8454  CImgDisplay& disp10) {
8455  disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event =
8456  disp6._is_event = disp7._is_event = disp8._is_event = disp9._is_event = disp10._is_event = false;
8457  while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed ||
8458  !disp6._is_closed || !disp7._is_closed || !disp8._is_closed || !disp9._is_closed || !disp10._is_closed) &&
8459  !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event &&
8460  !disp6._is_event && !disp7._is_event && !disp8._is_event && !disp9._is_event && !disp10._is_event)
8461  wait_all();
8462  }
8463 
8464 #if cimg_display==0
8465 
8467  static void wait_all() {
8468  return _no_display_exception();
8469  }
8470 
8472 
8479  template<typename T>
8480  CImgDisplay& render(const CImg<T>& img) {
8481  return assign(img);
8482  }
8483 
8485 
8491  return assign();
8492  }
8493 
8494 
8496 
8503  template<typename T>
8504  static void screenshot(const int x0, const int y0, const int x1, const int y1, CImg<T>& img) {
8505  cimg::unused(x0,y0,x1,y1,&img);
8506  _no_display_exception();
8507  }
8508 
8510 
8513  template<typename T>
8514  const CImgDisplay& snapshot(CImg<T>& img) const {
8515  cimg::unused(img);
8516  _no_display_exception();
8517  return *this;
8518  }
8519 #endif
8520 
8521  // X11-based implementation
8522  //--------------------------
8523 #if cimg_display==1
8524 
8525  Atom _wm_window_atom, _wm_protocol_atom;
8526  Window _window, _background_window;
8527  Colormap _colormap;
8528  XImage *_image;
8529  void *_data;
8530 #ifdef cimg_use_xshm
8531  XShmSegmentInfo *_shminfo;
8532 #endif
8533 
8534  static int screen_width() {
8535  Display *const dpy = cimg::X11_attr().display;
8536  int res = 0;
8537  if (!dpy) {
8538  Display *const _dpy = XOpenDisplay(0);
8539  if (!_dpy)
8540  throw CImgDisplayException("CImgDisplay::screen_width(): Failed to open X11 display.");
8541  res = DisplayWidth(_dpy,DefaultScreen(_dpy));
8542  XCloseDisplay(_dpy);
8543  } else {
8544 #ifdef cimg_use_xrandr
8545  if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution)
8546  res = cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].width;
8547  else res = DisplayWidth(dpy,DefaultScreen(dpy));
8548 #else
8549  res = DisplayWidth(dpy,DefaultScreen(dpy));
8550 #endif
8551  }
8552  return res;
8553  }
8554 
8555  static int screen_height() {
8556  Display *const dpy = cimg::X11_attr().display;
8557  int res = 0;
8558  if (!dpy) {
8559  Display *const _dpy = XOpenDisplay(0);
8560  if (!_dpy)
8561  throw CImgDisplayException("CImgDisplay::screen_height(): Failed to open X11 display.");
8562  res = DisplayHeight(_dpy,DefaultScreen(_dpy));
8563  XCloseDisplay(_dpy);
8564  } else {
8565 #ifdef cimg_use_xrandr
8566  if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution)
8567  res = cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].height;
8568  else res = DisplayHeight(dpy,DefaultScreen(dpy));
8569 #else
8570  res = DisplayHeight(dpy,DefaultScreen(dpy));
8571 #endif
8572  }
8573  return res;
8574  }
8575 
8576  static void wait_all() {
8577  if (!cimg::X11_attr().display) return;
8578  pthread_mutex_lock(&cimg::X11_attr().wait_event_mutex);
8579  pthread_cond_wait(&cimg::X11_attr().wait_event,&cimg::X11_attr().wait_event_mutex);
8580  pthread_mutex_unlock(&cimg::X11_attr().wait_event_mutex);
8581  }
8582 
8583  void _handle_events(const XEvent *const pevent) {
8584  Display *const dpy = cimg::X11_attr().display;
8585  XEvent event = *pevent;
8586  switch (event.type) {
8587  case ClientMessage : {
8588  if ((int)event.xclient.message_type==(int)_wm_protocol_atom &&
8589  (int)event.xclient.data.l[0]==(int)_wm_window_atom) {
8590  XUnmapWindow(cimg::X11_attr().display,_window);
8591  _is_closed = _is_event = true;
8592  pthread_cond_broadcast(&cimg::X11_attr().wait_event);
8593  }
8594  } break;
8595  case ConfigureNotify : {
8596  while (XCheckWindowEvent(dpy,_window,StructureNotifyMask,&event)) {}
8597  const unsigned int nw = event.xconfigure.width, nh = event.xconfigure.height;
8598  const int nx = event.xconfigure.x, ny = event.xconfigure.y;
8599  if (nw && nh && (nw!=_window_width || nh!=_window_height)) {
8600  _window_width = nw; _window_height = nh; _mouse_x = _mouse_y = -1;
8601  XResizeWindow(dpy,_window,_window_width,_window_height);
8602  _is_resized = _is_event = true;
8603  pthread_cond_broadcast(&cimg::X11_attr().wait_event);
8604  }
8605  if (nx!=_window_x || ny!=_window_y) {
8606  _window_x = nx; _window_y = ny; _is_moved = _is_event = true;
8607  pthread_cond_broadcast(&cimg::X11_attr().wait_event);
8608  }
8609  } break;
8610  case Expose : {
8611  while (XCheckWindowEvent(dpy,_window,ExposureMask,&event)) {}
8612  _paint(false);
8613  if (_is_fullscreen) {
8614  XWindowAttributes attr;
8615  XGetWindowAttributes(dpy,_window,&attr);
8616  while (attr.map_state!=IsViewable) XSync(dpy,0);
8617  XSetInputFocus(dpy,_window,RevertToParent,CurrentTime);
8618  }
8619  } break;
8620  case ButtonPress : {
8621  do {
8622  _mouse_x = event.xmotion.x; _mouse_y = event.xmotion.y;
8623  if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1;
8624  switch (event.xbutton.button) {
8625  case 1 : set_button(1); break;
8626  case 3 : set_button(2); break;
8627  case 2 : set_button(3); break;
8628  }
8629  } while (XCheckWindowEvent(dpy,_window,ButtonPressMask,&event));
8630  } break;
8631  case ButtonRelease : {
8632  do {
8633  _mouse_x = event.xmotion.x; _mouse_y = event.xmotion.y;
8634  if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1;
8635  switch (event.xbutton.button) {
8636  case 1 : set_button(1,false); break;
8637  case 3 : set_button(2,false); break;
8638  case 2 : set_button(3,false); break;
8639  case 4 : set_wheel(1); break;
8640  case 5 : set_wheel(-1); break;
8641  }
8642  } while (XCheckWindowEvent(dpy,_window,ButtonReleaseMask,&event));
8643  } break;
8644  case KeyPress : {
8645  char tmp = 0; KeySym ksym;
8646  XLookupString(&event.xkey,&tmp,1,&ksym,0);
8647  set_key((unsigned int)ksym,true);
8648  } break;
8649  case KeyRelease : {
8650  char keys_return[32]; // Check that the key has been physically unpressed.
8651  XQueryKeymap(dpy,keys_return);
8652  const unsigned int kc = event.xkey.keycode, kc1 = kc/8, kc2 = kc%8;
8653  const bool is_key_pressed = kc1>=32?false:(keys_return[kc1]>>kc2)&1;
8654  if (!is_key_pressed) {
8655  char tmp = 0; KeySym ksym;
8656  XLookupString(&event.xkey,&tmp,1,&ksym,0);
8657  set_key((unsigned int)ksym,false);
8658  }
8659  } break;
8660  case EnterNotify: {
8661  while (XCheckWindowEvent(dpy,_window,EnterWindowMask,&event)) {}
8662  _mouse_x = event.xmotion.x;
8663  _mouse_y = event.xmotion.y;
8664  if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1;
8665  } break;
8666  case LeaveNotify : {
8667  while (XCheckWindowEvent(dpy,_window,LeaveWindowMask,&event)) {}
8668  _mouse_x = _mouse_y = -1; _is_event = true;
8669  pthread_cond_broadcast(&cimg::X11_attr().wait_event);
8670  } break;
8671  case MotionNotify : {
8672  while (XCheckWindowEvent(dpy,_window,PointerMotionMask,&event)) {}
8673  _mouse_x = event.xmotion.x;
8674  _mouse_y = event.xmotion.y;
8675  if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1;
8676  _is_event = true;
8677  pthread_cond_broadcast(&cimg::X11_attr().wait_event);
8678  } break;
8679  }
8680  }
8681 
8682  static void* _events_thread(void *arg) { // Thread to manage events for all opened display windows.
8683  Display *const dpy = cimg::X11_attr().display;
8684  XEvent event;
8685  pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
8686  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
8687  if (!arg) for ( ; ; ) {
8688  cimg_lock_display();
8689  bool event_flag = XCheckTypedEvent(dpy,ClientMessage,&event);
8690  if (!event_flag) event_flag = XCheckMaskEvent(dpy,
8691  ExposureMask | StructureNotifyMask | ButtonPressMask |
8692  KeyPressMask | PointerMotionMask | EnterWindowMask |
8693  LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask,&event);
8694  if (event_flag)
8695  for (unsigned int i = 0; i<cimg::X11_attr().nb_wins; ++i)
8696  if (!cimg::X11_attr().wins[i]->_is_closed && event.xany.window==cimg::X11_attr().wins[i]->_window)
8697  cimg::X11_attr().wins[i]->_handle_events(&event);
8698  cimg_unlock_display();
8699  pthread_testcancel();
8700  cimg::sleep(8);
8701  }
8702  return 0;
8703  }
8704 
8705  void _set_colormap(Colormap& _colormap, const unsigned int dim) {
8706  XColor *const colormap = new XColor[256];
8707  switch (dim) {
8708  case 1 : { // colormap for greyscale images
8709  for (unsigned int index = 0; index<256; ++index) {
8710  colormap[index].pixel = index;
8711  colormap[index].red = colormap[index].green = colormap[index].blue = (unsigned short)(index<<8);
8712  colormap[index].flags = DoRed | DoGreen | DoBlue;
8713  }
8714  } break;
8715  case 2 : { // colormap for RG images
8716  for (unsigned int index = 0, r = 8; r<256; r+=16)
8717  for (unsigned int g = 8; g<256; g+=16) {
8718  colormap[index].pixel = index;
8719  colormap[index].red = colormap[index].blue = (unsigned short)(r<<8);
8720  colormap[index].green = (unsigned short)(g<<8);
8721  colormap[index++].flags = DoRed | DoGreen | DoBlue;
8722  }
8723  } break;
8724  default : { // colormap for RGB images
8725  for (unsigned int index = 0, r = 16; r<256; r+=32)
8726  for (unsigned int g = 16; g<256; g+=32)
8727  for (unsigned int b = 32; b<256; b+=64) {
8728  colormap[index].pixel = index;
8729  colormap[index].red = (unsigned short)(r<<8);
8730  colormap[index].green = (unsigned short)(g<<8);
8731  colormap[index].blue = (unsigned short)(b<<8);
8732  colormap[index++].flags = DoRed | DoGreen | DoBlue;
8733  }
8734  }
8735  }
8736  XStoreColors(cimg::X11_attr().display,_colormap,colormap,256);
8737  delete[] colormap;
8738  }
8739 
8740  void _map_window() {
8741  Display *const dpy = cimg::X11_attr().display;
8742  bool is_exposed = false, is_mapped = false;
8743  XWindowAttributes attr;
8744  XEvent event;
8745  XMapRaised(dpy,_window);
8746  do { // Wait for the window to be mapped.
8747  XWindowEvent(dpy,_window,StructureNotifyMask | ExposureMask,&event);
8748  switch (event.type) {
8749  case MapNotify : is_mapped = true; break;
8750  case Expose : is_exposed = true; break;
8751  }
8752  } while (!is_exposed || !is_mapped);
8753  do { // Wait for the window to be visible.
8754  XGetWindowAttributes(dpy,_window,&attr);
8755  if (attr.map_state!=IsViewable) { XSync(dpy,0); cimg::sleep(10); }
8756  } while (attr.map_state!=IsViewable);
8757  _window_x = attr.x;
8758  _window_y = attr.y;
8759  }
8760 
8761  void _paint(const bool wait_expose=true) {
8762  if (_is_closed || !_image) return;
8763  Display *const dpy = cimg::X11_attr().display;
8764  if (wait_expose) { // Send an expose event sticked to display window to force repaint.
8765  XEvent event;
8766  event.xexpose.type = Expose;
8767  event.xexpose.serial = 0;
8768  event.xexpose.send_event = 1;
8769  event.xexpose.display = dpy;
8770  event.xexpose.window = _window;
8771  event.xexpose.x = 0;
8772  event.xexpose.y = 0;
8773  event.xexpose.width = width();
8774  event.xexpose.height = height();
8775  event.xexpose.count = 0;
8776  XSendEvent(dpy,_window,0,0,&event);
8777  } else { // Repaint directly (may be called from the expose event).
8778  GC gc = DefaultGC(dpy,DefaultScreen(dpy));
8779 #ifdef cimg_use_xshm
8780  if (_shminfo) XShmPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height,1);
8781  else XPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height);
8782 #else
8783  XPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height);
8784 #endif
8785  }
8786  }
8787 
8788  template<typename T>
8789  void _resize(T pixel_type, const unsigned int ndimx, const unsigned int ndimy, const bool force_redraw) {
8790  Display *const dpy = cimg::X11_attr().display;
8791  cimg::unused(pixel_type);
8792 
8793 #ifdef cimg_use_xshm
8794  if (_shminfo) {
8795  XShmSegmentInfo *const nshminfo = new XShmSegmentInfo;
8796  XImage *const nimage = XShmCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),
8797  cimg::X11_attr().nb_bits,ZPixmap,0,nshminfo,ndimx,ndimy);
8798  if (!nimage) { delete nshminfo; return; }
8799  else {
8800  nshminfo->shmid = shmget(IPC_PRIVATE,ndimx*ndimy*sizeof(T),IPC_CREAT | 0777);
8801  if (nshminfo->shmid==-1) { XDestroyImage(nimage); delete nshminfo; return; }
8802  else {
8803  nshminfo->shmaddr = nimage->data = (char*)shmat(nshminfo->shmid,0,0);
8804  if (nshminfo->shmaddr==(char*)-1) {
8805  shmctl(nshminfo->shmid,IPC_RMID,0); XDestroyImage(nimage); delete nshminfo; return;
8806  } else {
8807  nshminfo->readOnly = 0;
8808  cimg::X11_attr().is_shm_enabled = true;
8809  XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
8810  XShmAttach(dpy,nshminfo);
8811  XFlush(dpy);
8812  XSetErrorHandler(oldXErrorHandler);
8813  if (!cimg::X11_attr().is_shm_enabled) {
8814  shmdt(nshminfo->shmaddr);
8815  shmctl(nshminfo->shmid,IPC_RMID,0);
8816  XDestroyImage(nimage);
8817  delete nshminfo;
8818  return;
8819  } else {
8820  T *const ndata = (T*)nimage->data;
8821  if (force_redraw) _render_resize((T*)_data,_width,_height,ndata,ndimx,ndimy);
8822  else std::memset(ndata,0,sizeof(T)*ndimx*ndimy);
8823  XShmDetach(dpy,_shminfo);
8824  XDestroyImage(_image);
8825  shmdt(_shminfo->shmaddr);
8826  shmctl(_shminfo->shmid,IPC_RMID,0);
8827  delete _shminfo;
8828  _shminfo = nshminfo;
8829  _image = nimage;
8830  _data = (void*)ndata;
8831  }
8832  }
8833  }
8834  }
8835  } else
8836 #endif
8837  {
8838  T *ndata = (T*)std::malloc(ndimx*ndimy*sizeof(T));
8839  if (force_redraw) _render_resize((T*)_data,_width,_height,ndata,ndimx,ndimy);
8840  else std::memset(ndata,0,sizeof(T)*ndimx*ndimy);
8841  _data = (void*)ndata;
8842  XDestroyImage(_image);
8843  _image = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),
8844  cimg::X11_attr().nb_bits,ZPixmap,0,(char*)_data,ndimx,ndimy,8,0);
8845  }
8846  }
8847 
8848  void _init_fullscreen() {
8849  if (!_is_fullscreen || _is_closed) return;
8850  Display *const dpy = cimg::X11_attr().display;
8851  _background_window = 0;
8852 
8853 #ifdef cimg_use_xrandr
8854  int foo;
8855  if (XRRQueryExtension(dpy,&foo,&foo)) {
8856  XRRRotations(dpy,DefaultScreen(dpy),&cimg::X11_attr().curr_rotation);
8857  if (!cimg::X11_attr().resolutions) {
8858  cimg::X11_attr().resolutions = XRRSizes(dpy,DefaultScreen(dpy),&foo);
8859  cimg::X11_attr().nb_resolutions = (unsigned int)foo;
8860  }
8861  if (cimg::X11_attr().resolutions) {
8862  cimg::X11_attr().curr_resolution = 0;
8863  for (unsigned int i = 0; i<cimg::X11_attr().nb_resolutions; ++i) {
8864  const unsigned int
8865  nw = (unsigned int)(cimg::X11_attr().resolutions[i].width),
8866  nh = (unsigned int)(cimg::X11_attr().resolutions[i].height);
8867  if (nw>=_width && nh>=_height &&
8868  nw<=(unsigned int)(cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].width) &&
8869  nh<=(unsigned int)(cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].height))
8870  cimg::X11_attr().curr_resolution = i;
8871  }
8872  if (cimg::X11_attr().curr_resolution>0) {
8873  XRRScreenConfiguration *config = XRRGetScreenInfo(dpy,DefaultRootWindow(dpy));
8874  XRRSetScreenConfig(dpy,config,DefaultRootWindow(dpy),
8875  cimg::X11_attr().curr_resolution,cimg::X11_attr().curr_rotation,CurrentTime);
8876  XRRFreeScreenConfigInfo(config);
8877  XSync(dpy,0);
8878  }
8879  }
8880  }
8881  if (!cimg::X11_attr().resolutions)
8882  cimg::warn(_cimgdisplay_instance
8883  "init_fullscreen(): Xrandr extension not supported by the X server.",
8884  cimgdisplay_instance);
8885 #endif
8886 
8887  const unsigned int sx = screen_width(), sy = screen_height();
8888  if (sx==_width && sy==_height) return;
8889  XSetWindowAttributes winattr;
8890  winattr.override_redirect = 1;
8891  _background_window = XCreateWindow(dpy,DefaultRootWindow(dpy),0,0,sx,sy,0,0,
8892  InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);
8893  const cimg_ulong buf_size = (cimg_ulong)sx*sy*(cimg::X11_attr().nb_bits==8?1:
8894  (cimg::X11_attr().nb_bits==16?2:4));
8895  void *background_data = std::malloc(buf_size);
8896  std::memset(background_data,0,buf_size);
8897  XImage *background_image = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),cimg::X11_attr().nb_bits,
8898  ZPixmap,0,(char*)background_data,sx,sy,8,0);
8899  XEvent event;
8900  XSelectInput(dpy,_background_window,StructureNotifyMask);
8901  XMapRaised(dpy,_background_window);
8902  do XWindowEvent(dpy,_background_window,StructureNotifyMask,&event);
8903  while (event.type!=MapNotify);
8904  GC gc = DefaultGC(dpy,DefaultScreen(dpy));
8905 #ifdef cimg_use_xshm
8906  if (_shminfo) XShmPutImage(dpy,_background_window,gc,background_image,0,0,0,0,sx,sy,0);
8907  else XPutImage(dpy,_background_window,gc,background_image,0,0,0,0,sx,sy);
8908 #else
8909  XPutImage(dpy,_background_window,gc,background_image,0,0,0,0,sx,sy);
8910 #endif
8911  XWindowAttributes attr;
8912  XGetWindowAttributes(dpy,_background_window,&attr);
8913  while (attr.map_state!=IsViewable) XSync(dpy,0);
8914  XDestroyImage(background_image);
8915  }
8916 
8917  void _desinit_fullscreen() {
8918  if (!_is_fullscreen) return;
8919  Display *const dpy = cimg::X11_attr().display;
8920  XUngrabKeyboard(dpy,CurrentTime);
8921 #ifdef cimg_use_xrandr
8922  if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution) {
8923  XRRScreenConfiguration *config = XRRGetScreenInfo(dpy,DefaultRootWindow(dpy));
8924  XRRSetScreenConfig(dpy,config,DefaultRootWindow(dpy),0,cimg::X11_attr().curr_rotation,CurrentTime);
8925  XRRFreeScreenConfigInfo(config);
8926  XSync(dpy,0);
8927  cimg::X11_attr().curr_resolution = 0;
8928  }
8929 #endif
8930  if (_background_window) XDestroyWindow(dpy,_background_window);
8931  _background_window = 0;
8932  _is_fullscreen = false;
8933  }
8934 
8935  static int _assign_xshm(Display *dpy, XErrorEvent *error) {
8936  cimg::unused(dpy,error);
8937  cimg::X11_attr().is_shm_enabled = false;
8938  return 0;
8939  }
8940 
8941  void _assign(const unsigned int dimw, const unsigned int dimh, const char *const ptitle=0,
8942  const unsigned int normalization_type=3,
8943  const bool fullscreen_flag=false, const bool closed_flag=false) {
8944  cimg::mutex(14);
8945 
8946  // Allocate space for window title
8947  const char *const nptitle = ptitle?ptitle:"";
8948  const unsigned int s = (unsigned int)std::strlen(nptitle) + 1;
8949  char *const tmp_title = s?new char[s]:0;
8950  if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char));
8951 
8952  // Destroy previous display window if existing
8953  if (!is_empty()) assign();
8954 
8955  // Open X11 display and retrieve graphical properties.
8956  Display* &dpy = cimg::X11_attr().display;
8957  if (!dpy) {
8958  dpy = XOpenDisplay(0);
8959  if (!dpy)
8960  throw CImgDisplayException(_cimgdisplay_instance
8961  "assign(): Failed to open X11 display.",
8962  cimgdisplay_instance);
8963 
8964  cimg::X11_attr().nb_bits = DefaultDepth(dpy,DefaultScreen(dpy));
8965  if (cimg::X11_attr().nb_bits!=8 && cimg::X11_attr().nb_bits!=16 &&
8966  cimg::X11_attr().nb_bits!=24 && cimg::X11_attr().nb_bits!=32)
8967  throw CImgDisplayException(_cimgdisplay_instance
8968  "assign(): Invalid %u bits screen mode detected "
8969  "(only 8, 16, 24 and 32 bits modes are managed).",
8970  cimgdisplay_instance,
8971  cimg::X11_attr().nb_bits);
8972  XVisualInfo vtemplate;
8973  vtemplate.visualid = XVisualIDFromVisual(DefaultVisual(dpy,DefaultScreen(dpy)));
8974  int nb_visuals;
8975  XVisualInfo *vinfo = XGetVisualInfo(dpy,VisualIDMask,&vtemplate,&nb_visuals);
8976  if (vinfo && vinfo->red_mask<vinfo->blue_mask) cimg::X11_attr().is_blue_first = true;
8977  cimg::X11_attr().byte_order = ImageByteOrder(dpy);
8978  XFree(vinfo);
8979 
8980  cimg_lock_display();
8981  cimg::X11_attr().events_thread = new pthread_t;
8982  pthread_create(cimg::X11_attr().events_thread,0,_events_thread,0);
8983  } else cimg_lock_display();
8984 
8985  // Set display variables.
8986  _width = std::min(dimw,(unsigned int)screen_width());
8987  _height = std::min(dimh,(unsigned int)screen_height());
8988  _normalization = normalization_type<4?normalization_type:3;
8989  _is_fullscreen = fullscreen_flag;
8990  _window_x = _window_y = 0;
8991  _is_closed = closed_flag;
8992  _title = tmp_title;
8993  flush();
8994 
8995  // Create X11 window (and LUT, if 8bits display)
8996  if (_is_fullscreen) {
8997  if (!_is_closed) _init_fullscreen();
8998  const unsigned int sx = screen_width(), sy = screen_height();
8999  XSetWindowAttributes winattr;
9000  winattr.override_redirect = 1;
9001  _window = XCreateWindow(dpy,DefaultRootWindow(dpy),(sx - _width)/2,(sy - _height)/2,_width,_height,0,0,
9002  InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);
9003  } else
9004  _window = XCreateSimpleWindow(dpy,DefaultRootWindow(dpy),0,0,_width,_height,0,0L,0L);
9005 
9006  XSelectInput(dpy,_window,
9007  ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask | PointerMotionMask |
9008  EnterWindowMask | LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask);
9009 
9010  XStoreName(dpy,_window,_title?_title:" ");
9011  if (cimg::X11_attr().nb_bits==8) {
9012  _colormap = XCreateColormap(dpy,_window,DefaultVisual(dpy,DefaultScreen(dpy)),AllocAll);
9013  _set_colormap(_colormap,3);
9014  XSetWindowColormap(dpy,_window,_colormap);
9015  }
9016 
9017  static const char *const _window_class = cimg_appname;
9018  XClassHint *const window_class = XAllocClassHint();
9019  window_class->res_name = (char*)_window_class;
9020  window_class->res_class = (char*)_window_class;
9021  XSetClassHint(dpy,_window,window_class);
9022  XFree(window_class);
9023 
9024  _window_width = _width;
9025  _window_height = _height;
9026 
9027  // Create XImage
9028 #ifdef cimg_use_xshm
9029  _shminfo = 0;
9030  if (XShmQueryExtension(dpy)) {
9031  _shminfo = new XShmSegmentInfo;
9032  _image = XShmCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),cimg::X11_attr().nb_bits,
9033  ZPixmap,0,_shminfo,_width,_height);
9034  if (!_image) { delete _shminfo; _shminfo = 0; }
9035  else {
9036  _shminfo->shmid = shmget(IPC_PRIVATE,_image->bytes_per_line*_image->height,IPC_CREAT|0777);
9037  if (_shminfo->shmid==-1) { XDestroyImage(_image); delete _shminfo; _shminfo = 0; }
9038  else {
9039  _shminfo->shmaddr = _image->data = (char*)(_data = shmat(_shminfo->shmid,0,0));
9040  if (_shminfo->shmaddr==(char*)-1) {
9041  shmctl(_shminfo->shmid,IPC_RMID,0); XDestroyImage(_image); delete _shminfo; _shminfo = 0;
9042  } else {
9043  _shminfo->readOnly = 0;
9044  cimg::X11_attr().is_shm_enabled = true;
9045  XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
9046  XShmAttach(dpy,_shminfo);
9047  XSync(dpy,0);
9048  XSetErrorHandler(oldXErrorHandler);
9049  if (!cimg::X11_attr().is_shm_enabled) {
9050  shmdt(_shminfo->shmaddr); shmctl(_shminfo->shmid,IPC_RMID,0); XDestroyImage(_image);
9051  delete _shminfo; _shminfo = 0;
9052  }
9053  }
9054  }
9055  }
9056  }
9057  if (!_shminfo)
9058 #endif
9059  {
9060  const cimg_ulong buf_size = (cimg_ulong)_width*_height*(cimg::X11_attr().nb_bits==8?1:
9061  (cimg::X11_attr().nb_bits==16?2:4));
9062  _data = std::malloc(buf_size);
9063  _image = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),cimg::X11_attr().nb_bits,
9064  ZPixmap,0,(char*)_data,_width,_height,8,0);
9065  }
9066 
9067  _wm_window_atom = XInternAtom(dpy,"WM_DELETE_WINDOW",0);
9068  _wm_protocol_atom = XInternAtom(dpy,"WM_PROTOCOLS",0);
9069  XSetWMProtocols(dpy,_window,&_wm_window_atom,1);
9070 
9071  if (_is_fullscreen) XGrabKeyboard(dpy,_window,1,GrabModeAsync,GrabModeAsync,CurrentTime);
9072  cimg::X11_attr().wins[cimg::X11_attr().nb_wins++]=this;
9073  if (!_is_closed) _map_window(); else { _window_x = _window_y = cimg::type<int>::min(); }
9074  cimg_unlock_display();
9075  cimg::mutex(14,0);
9076  }
9077 
9078  CImgDisplay& assign() {
9079  if (is_empty()) return flush();
9080  Display *const dpy = cimg::X11_attr().display;
9081  cimg_lock_display();
9082 
9083  // Remove display window from event thread list.
9084  unsigned int i;
9085  for (i = 0; i<cimg::X11_attr().nb_wins && cimg::X11_attr().wins[i]!=this; ++i) {}
9086  for ( ; i<cimg::X11_attr().nb_wins - 1; ++i) cimg::X11_attr().wins[i] = cimg::X11_attr().wins[i + 1];
9087  --cimg::X11_attr().nb_wins;
9088 
9089  // Destroy window, image, colormap and title.
9090  if (_is_fullscreen && !_is_closed) _desinit_fullscreen();
9091  XDestroyWindow(dpy,_window);
9092  _window = 0;
9093 #ifdef cimg_use_xshm
9094  if (_shminfo) {
9095  XShmDetach(dpy,_shminfo);
9096  XDestroyImage(_image);
9097  shmdt(_shminfo->shmaddr);
9098  shmctl(_shminfo->shmid,IPC_RMID,0);
9099  delete _shminfo;
9100  _shminfo = 0;
9101  } else
9102 #endif
9103  XDestroyImage(_image);
9104  _data = 0; _image = 0;
9105  if (cimg::X11_attr().nb_bits==8) XFreeColormap(dpy,_colormap);
9106  _colormap = 0;
9107  XSync(dpy,0);
9108 
9109  // Reset display variables.
9110  delete[] _title;
9111  _width = _height = _normalization = _window_width = _window_height = 0;
9112  _window_x = _window_y = 0;
9113  _is_fullscreen = false;
9114  _is_closed = true;
9115  _min = _max = 0;
9116  _title = 0;
9117  flush();
9118 
9119  cimg_unlock_display();
9120  return *this;
9121  }
9122 
9123  CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *const title=0,
9124  const unsigned int normalization_type=3,
9125  const bool fullscreen_flag=false, const bool closed_flag=false) {
9126  if (!dimw || !dimh) return assign();
9127  _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
9128  _min = _max = 0;
9129  std::memset(_data,0,(cimg::X11_attr().nb_bits==8?sizeof(unsigned char):
9130  (cimg::X11_attr().nb_bits==16?sizeof(unsigned short):sizeof(unsigned int)))*
9131  (size_t)_width*_height);
9132  return paint();
9133  }
9134 
9135  template<typename T>
9136  CImgDisplay& assign(const CImg<T>& img, const char *const title=0,
9137  const unsigned int normalization_type=3,
9138  const bool fullscreen_flag=false, const bool closed_flag=false) {
9139  if (!img) return assign();
9140  CImg<T> tmp;
9141  const CImg<T>& nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2,
9142  (img._height - 1)/2,
9143  (img._depth - 1)/2));
9144  _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag);
9145  if (_normalization==2) _min = (float)nimg.min_max(_max);
9146  return render(nimg).paint();
9147  }
9148 
9149  template<typename T>
9150  CImgDisplay& assign(const CImgList<T>& list, const char *const title=0,
9151  const unsigned int normalization_type=3,
9152  const bool fullscreen_flag=false, const bool closed_flag=false) {
9153  if (!list) return assign();
9154  CImg<T> tmp;
9155  const CImg<T> img = list>'x', &nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2,
9156  (img._height - 1)/2,
9157  (img._depth - 1)/2));
9158  _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag);
9159  if (_normalization==2) _min = (float)nimg.min_max(_max);
9160  return render(nimg).paint();
9161  }
9162 
9163  CImgDisplay& assign(const CImgDisplay& disp) {
9164  if (!disp) return assign();
9165  _assign(disp._width,disp._height,disp._title,disp._normalization,disp._is_fullscreen,disp._is_closed);
9166  std::memcpy(_data,disp._data,(cimg::X11_attr().nb_bits==8?sizeof(unsigned char):
9167  cimg::X11_attr().nb_bits==16?sizeof(unsigned short):
9168  sizeof(unsigned int))*(size_t)_width*_height);
9169  return paint();
9170  }
9171 
9172  CImgDisplay& resize(const int nwidth, const int nheight, const bool force_redraw=true) {
9173  if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
9174  if (is_empty()) return assign(nwidth,nheight);
9175  Display *const dpy = cimg::X11_attr().display;
9176  const unsigned int
9177  tmpdimx = (nwidth>0)?nwidth:(-nwidth*width()/100),
9178  tmpdimy = (nheight>0)?nheight:(-nheight*height()/100),
9179  dimx = tmpdimx?tmpdimx:1,
9180  dimy = tmpdimy?tmpdimy:1;
9181  if (_width!=dimx || _height!=dimy || _window_width!=dimx || _window_height!=dimy) {
9182  show();
9183  cimg_lock_display();
9184  if (_window_width!=dimx || _window_height!=dimy) {
9185  XWindowAttributes attr;
9186  for (unsigned int i = 0; i<10; ++i) {
9187  XResizeWindow(dpy,_window,dimx,dimy);
9188  XGetWindowAttributes(dpy,_window,&attr);
9189  if (attr.width==(int)dimx && attr.height==(int)dimy) break;
9190  cimg::wait(5);
9191  }
9192  }
9193  if (_width!=dimx || _height!=dimy) switch (cimg::X11_attr().nb_bits) {
9194  case 8 : { unsigned char pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break;
9195  case 16 : { unsigned short pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break;
9196  default : { unsigned int pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); }
9197  }
9198  _window_width = _width = dimx; _window_height = _height = dimy;
9199  cimg_unlock_display();
9200  }
9201  _is_resized = false;
9202  if (_is_fullscreen) move((screen_width() - _width)/2,(screen_height() - _height)/2);
9203  if (force_redraw) return paint();
9204  return *this;
9205  }
9206 
9207  CImgDisplay& toggle_fullscreen(const bool force_redraw=true) {
9208  if (is_empty()) return *this;
9209  if (force_redraw) {
9210  const cimg_ulong buf_size = (cimg_ulong)_width*_height*
9211  (cimg::X11_attr().nb_bits==8?1:(cimg::X11_attr().nb_bits==16?2:4));
9212  void *image_data = std::malloc(buf_size);
9213  std::memcpy(image_data,_data,buf_size);
9214  assign(_width,_height,_title,_normalization,!_is_fullscreen,false);
9215  std::memcpy(_data,image_data,buf_size);
9216  std::free(image_data);
9217  return paint();
9218  }
9219  return assign(_width,_height,_title,_normalization,!_is_fullscreen,false);
9220  }
9221 
9222  CImgDisplay& show() {
9223  if (is_empty() || !_is_closed) return *this;
9224  cimg_lock_display();
9225  if (_is_fullscreen) _init_fullscreen();
9226  _map_window();
9227  _is_closed = false;
9228  cimg_unlock_display();
9229  return paint();
9230  }
9231 
9232  CImgDisplay& close() {
9233  if (is_empty() || _is_closed) return *this;
9234  Display *const dpy = cimg::X11_attr().display;
9235  cimg_lock_display();
9236  if (_is_fullscreen) _desinit_fullscreen();
9237  XUnmapWindow(dpy,_window);
9238  _window_x = _window_y = -1;
9239  _is_closed = true;
9240  cimg_unlock_display();
9241  return *this;
9242  }
9243 
9244  CImgDisplay& move(const int posx, const int posy) {
9245  if (is_empty()) return *this;
9246  if (_window_x!=posx || _window_y!=posy) {
9247  show();
9248  Display *const dpy = cimg::X11_attr().display;
9249  cimg_lock_display();
9250  XMoveWindow(dpy,_window,posx,posy);
9251  _window_x = posx; _window_y = posy;
9252  cimg_unlock_display();
9253  }
9254  _is_moved = false;
9255  return paint();
9256  }
9257 
9258  CImgDisplay& show_mouse() {
9259  if (is_empty()) return *this;
9260  Display *const dpy = cimg::X11_attr().display;
9261  cimg_lock_display();
9262  XUndefineCursor(dpy,_window);
9263  cimg_unlock_display();
9264  return *this;
9265  }
9266 
9267  CImgDisplay& hide_mouse() {
9268  if (is_empty()) return *this;
9269  Display *const dpy = cimg::X11_attr().display;
9270  cimg_lock_display();
9271  static const char pix_data[8] = { 0 };
9272  XColor col;
9273  col.red = col.green = col.blue = 0;
9274  Pixmap pix = XCreateBitmapFromData(dpy,_window,pix_data,8,8);
9275  Cursor cur = XCreatePixmapCursor(dpy,pix,pix,&col,&col,0,0);
9276  XFreePixmap(dpy,pix);
9277  XDefineCursor(dpy,_window,cur);
9278  cimg_unlock_display();
9279  return *this;
9280  }
9281 
9282  CImgDisplay& set_mouse(const int posx, const int posy) {
9283  if (is_empty() || _is_closed) return *this;
9284  Display *const dpy = cimg::X11_attr().display;
9285  cimg_lock_display();
9286  XWarpPointer(dpy,0L,_window,0,0,0,0,posx,posy);
9287  _mouse_x = posx; _mouse_y = posy;
9288  _is_moved = false;
9289  XSync(dpy,0);
9290  cimg_unlock_display();
9291  return *this;
9292  }
9293 
9294  CImgDisplay& set_title(const char *const format, ...) {
9295  if (is_empty()) return *this;
9296  char *const tmp = new char[1024];
9297  va_list ap;
9298  va_start(ap, format);
9299  cimg_vsnprintf(tmp,1024,format,ap);
9300  va_end(ap);
9301  if (!std::strcmp(_title,tmp)) { delete[] tmp; return *this; }
9302  delete[] _title;
9303  const unsigned int s = (unsigned int)std::strlen(tmp) + 1;
9304  _title = new char[s];
9305  std::memcpy(_title,tmp,s*sizeof(char));
9306  Display *const dpy = cimg::X11_attr().display;
9307  cimg_lock_display();
9308  XStoreName(dpy,_window,tmp);
9309  cimg_unlock_display();
9310  delete[] tmp;
9311  return *this;
9312  }
9313 
9314  template<typename T>
9315  CImgDisplay& display(const CImg<T>& img) {
9316  if (!img)
9317  throw CImgArgumentException(_cimgdisplay_instance
9318  "display(): Empty specified image.",
9319  cimgdisplay_instance);
9320  if (is_empty()) return assign(img);
9321  return render(img).paint(false);
9322  }
9323 
9324  CImgDisplay& paint(const bool wait_expose=true) {
9325  if (is_empty()) return *this;
9326  cimg_lock_display();
9327  _paint(wait_expose);
9328  cimg_unlock_display();
9329  return *this;
9330  }
9331 
9332  template<typename T>
9333  CImgDisplay& render(const CImg<T>& img, const bool flag8=false) {
9334  if (!img)
9335  throw CImgArgumentException(_cimgdisplay_instance
9336  "render(): Empty specified image.",
9337  cimgdisplay_instance);
9338  if (is_empty()) return *this;
9339  if (img._depth!=1) return render(img.get_projections2d((img._width - 1)/2,(img._height - 1)/2,
9340  (img._depth - 1)/2));
9341  if (cimg::X11_attr().nb_bits==8 && (img._width!=_width || img._height!=_height))
9342  return render(img.get_resize(_width,_height,1,-100,1));
9343  if (cimg::X11_attr().nb_bits==8 && !flag8 && img._spectrum==3) {
9344  static const CImg<typename CImg<T>::ucharT> default_colormap = CImg<typename CImg<T>::ucharT>::default_LUT256();
9345  return render(img.get_index(default_colormap,1,false));
9346  }
9347 
9348  const T
9349  *data1 = img._data,
9350  *data2 = (img._spectrum>1)?img.data(0,0,0,1):data1,
9351  *data3 = (img._spectrum>2)?img.data(0,0,0,2):data1;
9352 
9353  if (cimg::X11_attr().is_blue_first) cimg::swap(data1,data3);
9354  cimg_lock_display();
9355 
9356  if (!_normalization || (_normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
9357  _min = _max = 0;
9358  switch (cimg::X11_attr().nb_bits) {
9359  case 8 : { // 256 colormap, no normalization
9360  _set_colormap(_colormap,img._spectrum);
9361  unsigned char
9362  *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data:
9363  new unsigned char[(size_t)img._width*img._height],
9364  *ptrd = (unsigned char*)ndata;
9365  switch (img._spectrum) {
9366  case 1 :
9367  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
9368  (*ptrd++) = (unsigned char)*(data1++);
9369  break;
9370  case 2 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9371  const unsigned char
9372  R = (unsigned char)*(data1++),
9373  G = (unsigned char)*(data2++);
9374  (*ptrd++) = (R&0xf0) | (G>>4);
9375  } break;
9376  default : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9377  const unsigned char
9378  R = (unsigned char)*(data1++),
9379  G = (unsigned char)*(data2++),
9380  B = (unsigned char)*(data3++);
9381  (*ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
9382  }
9383  }
9384  if (ndata!=_data) {
9385  _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height);
9386  delete[] ndata;
9387  }
9388  } break;
9389  case 16 : { // 16 bits colors, no normalization
9390  unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data:
9391  new unsigned short[(size_t)img._width*img._height];
9392  unsigned char *ptrd = (unsigned char*)ndata;
9393  const unsigned int M = 248;
9394  switch (img._spectrum) {
9395  case 1 :
9396  if (cimg::X11_attr().byte_order)
9397  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9398  const unsigned char val = (unsigned char)*(data1++), G = val>>2;
9399  ptrd[0] = (val&M) | (G>>3);
9400  ptrd[1] = (G<<5) | (G>>1);
9401  ptrd+=2;
9402  } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9403  const unsigned char val = (unsigned char)*(data1++), G = val>>2;
9404  ptrd[0] = (G<<5) | (G>>1);
9405  ptrd[1] = (val&M) | (G>>3);
9406  ptrd+=2;
9407  }
9408  break;
9409  case 2 :
9410  if (cimg::X11_attr().byte_order)
9411  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9412  const unsigned char G = (unsigned char)*(data2++)>>2;
9413  ptrd[0] = ((unsigned char)*(data1++)&M) | (G>>3);
9414  ptrd[1] = (G<<5);
9415  ptrd+=2;
9416  } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9417  const unsigned char G = (unsigned char)*(data2++)>>2;
9418  ptrd[0] = (G<<5);
9419  ptrd[1] = ((unsigned char)*(data1++)&M) | (G>>3);
9420  ptrd+=2;
9421  }
9422  break;
9423  default :
9424  if (cimg::X11_attr().byte_order)
9425  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9426  const unsigned char G = (unsigned char)*(data2++)>>2;
9427  ptrd[0] = ((unsigned char)*(data1++)&M) | (G>>3);
9428  ptrd[1] = (G<<5) | ((unsigned char)*(data3++)>>3);
9429  ptrd+=2;
9430  } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9431  const unsigned char G = (unsigned char)*(data2++)>>2;
9432  ptrd[0] = (G<<5) | ((unsigned char)*(data3++)>>3);
9433  ptrd[1] = ((unsigned char)*(data1++)&M) | (G>>3);
9434  ptrd+=2;
9435  }
9436  }
9437  if (ndata!=_data) {
9438  _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height);
9439  delete[] ndata;
9440  }
9441  } break;
9442  default : { // 24 bits colors, no normalization
9443  unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data:
9444  new unsigned int[(size_t)img._width*img._height];
9445  if (sizeof(int)==4) { // 32 bits int uses optimized version
9446  unsigned int *ptrd = ndata;
9447  switch (img._spectrum) {
9448  case 1 :
9449  if (cimg::X11_attr().byte_order==cimg::endianness())
9450  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9451  const unsigned char val = (unsigned char)*(data1++);
9452  *(ptrd++) = (val<<16) | (val<<8) | val;
9453  }
9454  else
9455  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9456  const unsigned char val = (unsigned char)*(data1++);
9457  *(ptrd++) = (val<<16) | (val<<8) | val;
9458  }
9459  break;
9460  case 2 :
9461  if (cimg::X11_attr().byte_order==cimg::endianness())
9462  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
9463  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
9464  else
9465  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
9466  *(ptrd++) = ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
9467  break;
9468  default :
9469  if (cimg::X11_attr().byte_order==cimg::endianness())
9470  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
9471  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) |
9472  (unsigned char)*(data3++);
9473  else
9474  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
9475  *(ptrd++) = ((unsigned char)*(data3++)<<24) | ((unsigned char)*(data2++)<<16) |
9476  ((unsigned char)*(data1++)<<8);
9477  }
9478  } else {
9479  unsigned char *ptrd = (unsigned char*)ndata;
9480  switch (img._spectrum) {
9481  case 1 :
9482  if (cimg::X11_attr().byte_order)
9483  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9484  ptrd[0] = 0;
9485  ptrd[1] = (unsigned char)*(data1++);
9486  ptrd[2] = 0;
9487  ptrd[3] = 0;
9488  ptrd+=4;
9489  } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9490  ptrd[0] = 0;
9491  ptrd[1] = 0;
9492  ptrd[2] = (unsigned char)*(data1++);
9493  ptrd[3] = 0;
9494  ptrd+=4;
9495  }
9496  break;
9497  case 2 :
9498  if (cimg::X11_attr().byte_order) cimg::swap(data1,data2);
9499  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9500  ptrd[0] = 0;
9501  ptrd[1] = (unsigned char)*(data2++);
9502  ptrd[2] = (unsigned char)*(data1++);
9503  ptrd[3] = 0;
9504  ptrd+=4;
9505  }
9506  break;
9507  default :
9508  if (cimg::X11_attr().byte_order)
9509  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9510  ptrd[0] = 0;
9511  ptrd[1] = (unsigned char)*(data1++);
9512  ptrd[2] = (unsigned char)*(data2++);
9513  ptrd[3] = (unsigned char)*(data3++);
9514  ptrd+=4;
9515  } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9516  ptrd[0] = (unsigned char)*(data3++);
9517  ptrd[1] = (unsigned char)*(data2++);
9518  ptrd[2] = (unsigned char)*(data1++);
9519  ptrd[3] = 0;
9520  ptrd+=4;
9521  }
9522  }
9523  }
9524  if (ndata!=_data) {
9525  _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height);
9526  delete[] ndata;
9527  }
9528  }
9529  }
9530  } else {
9531  if (_normalization==3) {
9532  if (cimg::type<T>::is_float()) _min = (float)img.min_max(_max);
9533  else { _min = (float)cimg::type<T>::min(); _max = (float)cimg::type<T>::max(); }
9534  } else if ((_min>_max) || _normalization==1) _min = (float)img.min_max(_max);
9535  const float delta = _max - _min, mm = 255/(delta?delta:1.0f);
9536  switch (cimg::X11_attr().nb_bits) {
9537  case 8 : { // 256 colormap, with normalization
9538  _set_colormap(_colormap,img._spectrum);
9539  unsigned char *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data:
9540  new unsigned char[(size_t)img._width*img._height];
9541  unsigned char *ptrd = (unsigned char*)ndata;
9542  switch (img._spectrum) {
9543  case 1 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9544  const unsigned char R = (unsigned char)((*(data1++) - _min)*mm);
9545  *(ptrd++) = R;
9546  } break;
9547  case 2 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9548  const unsigned char
9549  R = (unsigned char)((*(data1++) - _min)*mm),
9550  G = (unsigned char)((*(data2++) - _min)*mm);
9551  (*ptrd++) = (R&0xf0) | (G>>4);
9552  } break;
9553  default :
9554  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9555  const unsigned char
9556  R = (unsigned char)((*(data1++) - _min)*mm),
9557  G = (unsigned char)((*(data2++) - _min)*mm),
9558  B = (unsigned char)((*(data3++) - _min)*mm);
9559  *(ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
9560  }
9561  }
9562  if (ndata!=_data) {
9563  _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height);
9564  delete[] ndata;
9565  }
9566  } break;
9567  case 16 : { // 16 bits colors, with normalization
9568  unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data:
9569  new unsigned short[(size_t)img._width*img._height];
9570  unsigned char *ptrd = (unsigned char*)ndata;
9571  const unsigned int M = 248;
9572  switch (img._spectrum) {
9573  case 1 :
9574  if (cimg::X11_attr().byte_order)
9575  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9576  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm), G = val>>2;
9577  ptrd[0] = (val&M) | (G>>3);
9578  ptrd[1] = (G<<5) | (val>>3);
9579  ptrd+=2;
9580  } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9581  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm), G = val>>2;
9582  ptrd[0] = (G<<5) | (val>>3);
9583  ptrd[1] = (val&M) | (G>>3);
9584  ptrd+=2;
9585  }
9586  break;
9587  case 2 :
9588  if (cimg::X11_attr().byte_order)
9589  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9590  const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2;
9591  ptrd[0] = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3);
9592  ptrd[1] = (G<<5);
9593  ptrd+=2;
9594  } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9595  const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2;
9596  ptrd[0] = (G<<5);
9597  ptrd[1] = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3);
9598  ptrd+=2;
9599  }
9600  break;
9601  default :
9602  if (cimg::X11_attr().byte_order)
9603  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9604  const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2;
9605  ptrd[0] = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3);
9606  ptrd[1] = (G<<5) | ((unsigned char)((*(data3++) - _min)*mm)>>3);
9607  ptrd+=2;
9608  } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9609  const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2;
9610  ptrd[0] = (G<<5) | ((unsigned char)((*(data3++) - _min)*mm)>>3);
9611  ptrd[1] = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3);
9612  ptrd+=2;
9613  }
9614  }
9615  if (ndata!=_data) {
9616  _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height);
9617  delete[] ndata;
9618  }
9619  } break;
9620  default : { // 24 bits colors, with normalization
9621  unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data:
9622  new unsigned int[(size_t)img._width*img._height];
9623  if (sizeof(int)==4) { // 32 bits int uses optimized version
9624  unsigned int *ptrd = ndata;
9625  switch (img._spectrum) {
9626  case 1 :
9627  if (cimg::X11_attr().byte_order==cimg::endianness())
9628  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9629  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);
9630  *(ptrd++) = (val<<16) | (val<<8) | val;
9631  }
9632  else
9633  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9634  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);
9635  *(ptrd++) = (val<<24) | (val<<16) | (val<<8);
9636  }
9637  break;
9638  case 2 :
9639  if (cimg::X11_attr().byte_order==cimg::endianness())
9640  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
9641  *(ptrd++) =
9642  ((unsigned char)((*(data1++) - _min)*mm)<<16) |
9643  ((unsigned char)((*(data2++) - _min)*mm)<<8);
9644  else
9645  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
9646  *(ptrd++) =
9647  ((unsigned char)((*(data2++) - _min)*mm)<<16) |
9648  ((unsigned char)((*(data1++) - _min)*mm)<<8);
9649  break;
9650  default :
9651  if (cimg::X11_attr().byte_order==cimg::endianness())
9652  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
9653  *(ptrd++) =
9654  ((unsigned char)((*(data1++) - _min)*mm)<<16) |
9655  ((unsigned char)((*(data2++) - _min)*mm)<<8) |
9656  (unsigned char)((*(data3++) - _min)*mm);
9657  else
9658  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
9659  *(ptrd++) =
9660  ((unsigned char)((*(data3++) - _min)*mm)<<24) |
9661  ((unsigned char)((*(data2++) - _min)*mm)<<16) |
9662  ((unsigned char)((*(data1++) - _min)*mm)<<8);
9663  }
9664  } else {
9665  unsigned char *ptrd = (unsigned char*)ndata;
9666  switch (img._spectrum) {
9667  case 1 :
9668  if (cimg::X11_attr().byte_order)
9669  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9670  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);
9671  ptrd[0] = 0;
9672  ptrd[1] = val;
9673  ptrd[2] = val;
9674  ptrd[3] = val;
9675  ptrd+=4;
9676  } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9677  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);
9678  ptrd[0] = val;
9679  ptrd[1] = val;
9680  ptrd[2] = val;
9681  ptrd[3] = 0;
9682  ptrd+=4;
9683  }
9684  break;
9685  case 2 :
9686  if (cimg::X11_attr().byte_order) cimg::swap(data1,data2);
9687  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9688  ptrd[0] = 0;
9689  ptrd[1] = (unsigned char)((*(data2++) - _min)*mm);
9690  ptrd[2] = (unsigned char)((*(data1++) - _min)*mm);
9691  ptrd[3] = 0;
9692  ptrd+=4;
9693  }
9694  break;
9695  default :
9696  if (cimg::X11_attr().byte_order)
9697  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9698  ptrd[0] = 0;
9699  ptrd[1] = (unsigned char)((*(data1++) - _min)*mm);
9700  ptrd[2] = (unsigned char)((*(data2++) - _min)*mm);
9701  ptrd[3] = (unsigned char)((*(data3++) - _min)*mm);
9702  ptrd+=4;
9703  } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9704  ptrd[0] = (unsigned char)((*(data3++) - _min)*mm);
9705  ptrd[1] = (unsigned char)((*(data2++) - _min)*mm);
9706  ptrd[2] = (unsigned char)((*(data1++) - _min)*mm);
9707  ptrd[3] = 0;
9708  ptrd+=4;
9709  }
9710  }
9711  }
9712  if (ndata!=_data) {
9713  _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height);
9714  delete[] ndata;
9715  }
9716  }
9717  }
9718  }
9719  cimg_unlock_display();
9720  return *this;
9721  }
9722 
9723  template<typename T>
9724  static void screenshot(const int x0, const int y0, const int x1, const int y1, CImg<T>& img) {
9725  img.assign();
9726  Display *dpy = cimg::X11_attr().display;
9727  cimg_lock_display();
9728  if (!dpy) {
9729  dpy = XOpenDisplay(0);
9730  if (!dpy)
9731  throw CImgDisplayException("CImgDisplay::screenshot(): Failed to open X11 display.");
9732  }
9733  Window root = DefaultRootWindow(dpy);
9734  XWindowAttributes gwa;
9735  XGetWindowAttributes(dpy,root,&gwa);
9736  const int width = gwa.width, height = gwa.height;
9737  int _x0 = x0, _y0 = y0, _x1 = x1, _y1 = y1;
9738  if (_x0>_x1) cimg::swap(_x0,_x1);
9739  if (_y0>_y1) cimg::swap(_y0,_y1);
9740 
9741  XImage *image = 0;
9742  if (_x1>=0 && _x0<width && _y1>=0 && _y0<height) {
9743  _x0 = std::max(_x0,0);
9744  _y0 = std::max(_y0,0);
9745  _x1 = std::min(_x1,width - 1);
9746  _y1 = std::min(_y1,height - 1);
9747  image = XGetImage(dpy,root,_x0,_y0,_x1 - _x0 + 1,_y1 - _y0 + 1,AllPlanes,ZPixmap);
9748 
9749  if (image) {
9750  const unsigned long
9751  red_mask = image->red_mask,
9752  green_mask = image->green_mask,
9753  blue_mask = image->blue_mask;
9754  img.assign(image->width,image->height,1,3);
9755  T *pR = img.data(0,0,0,0), *pG = img.data(0,0,0,1), *pB = img.data(0,0,0,2);
9756  cimg_forXY(img,x,y) {
9757  const unsigned long pixel = XGetPixel(image,x,y);
9758  *(pR++) = (T)((pixel & red_mask)>>16);
9759  *(pG++) = (T)((pixel & green_mask)>>8);
9760  *(pB++) = (T)(pixel & blue_mask);
9761  }
9762  XDestroyImage(image);
9763  }
9764  }
9765  if (!cimg::X11_attr().display) XCloseDisplay(dpy);
9766  cimg_unlock_display();
9767  if (img.is_empty())
9768  throw CImgDisplayException("CImgDisplay::screenshot(): Failed to take screenshot "
9769  "with coordinates (%d,%d)-(%d,%d).",
9770  x0,y0,x1,y1);
9771  }
9772 
9773  template<typename T>
9774  const CImgDisplay& snapshot(CImg<T>& img) const {
9775  if (is_empty()) { img.assign(); return *this; }
9776  const unsigned char *ptrs = (unsigned char*)_data;
9777  img.assign(_width,_height,1,3);
9778  T
9779  *data1 = img.data(0,0,0,0),
9780  *data2 = img.data(0,0,0,1),
9781  *data3 = img.data(0,0,0,2);
9782  if (cimg::X11_attr().is_blue_first) cimg::swap(data1,data3);
9783  switch (cimg::X11_attr().nb_bits) {
9784  case 8 : {
9785  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9786  const unsigned char val = *(ptrs++);
9787  *(data1++) = (T)(val&0xe0);
9788  *(data2++) = (T)((val&0x1c)<<3);
9789  *(data3++) = (T)(val<<6);
9790  }
9791  } break;
9792  case 16 : {
9793  if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9794  const unsigned char
9795  val0 = ptrs[0],
9796  val1 = ptrs[1];
9797  ptrs+=2;
9798  *(data1++) = (T)(val0&0xf8);
9799  *(data2++) = (T)((val0<<5) | ((val1&0xe0)>>5));
9800  *(data3++) = (T)(val1<<3);
9801  } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9802  const unsigned short
9803  val0 = ptrs[0],
9804  val1 = ptrs[1];
9805  ptrs+=2;
9806  *(data1++) = (T)(val1&0xf8);
9807  *(data2++) = (T)((val1<<5) | ((val0&0xe0)>>5));
9808  *(data3++) = (T)(val0<<3);
9809  }
9810  } break;
9811  default : {
9812  if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9813  ++ptrs;
9814  *(data1++) = (T)ptrs[0];
9815  *(data2++) = (T)ptrs[1];
9816  *(data3++) = (T)ptrs[2];
9817  ptrs+=3;
9818  } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
9819  *(data3++) = (T)ptrs[0];
9820  *(data2++) = (T)ptrs[1];
9821  *(data1++) = (T)ptrs[2];
9822  ptrs+=3;
9823  ++ptrs;
9824  }
9825  }
9826  }
9827  return *this;
9828  }
9829 
9830  // Windows-based implementation.
9831  //-------------------------------
9832 #elif cimg_display==2
9833 
9834  bool _is_mouse_tracked, _is_cursor_visible;
9835  HANDLE _thread, _is_created, _mutex;
9836  HWND _window, _background_window;
9837  CLIENTCREATESTRUCT _ccs;
9838  unsigned int *_data;
9839  DEVMODE _curr_mode;
9840  BITMAPINFO _bmi;
9841  HDC _hdc;
9842 
9843  static int screen_width() {
9844  DEVMODE mode;
9845  mode.dmSize = sizeof(DEVMODE);
9846  mode.dmDriverExtra = 0;
9847  EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);
9848  return (int)mode.dmPelsWidth;
9849  }
9850 
9851  static int screen_height() {
9852  DEVMODE mode;
9853  mode.dmSize = sizeof(DEVMODE);
9854  mode.dmDriverExtra = 0;
9855  EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);
9856  return (int)mode.dmPelsHeight;
9857  }
9858 
9859  static void wait_all() {
9860  WaitForSingleObject(cimg::Win32_attr().wait_event,INFINITE);
9861  }
9862 
9863  static LRESULT APIENTRY _handle_events(HWND window, UINT msg, WPARAM wParam, LPARAM lParam) {
9864 #ifdef _WIN64
9865  CImgDisplay *const disp = (CImgDisplay*)GetWindowLongPtr(window,GWLP_USERDATA);
9866 #else
9867  CImgDisplay *const disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA);
9868 #endif
9869  MSG st_msg;
9870  switch (msg) {
9871  case WM_CLOSE :
9872  disp->_mouse_x = disp->_mouse_y = -1;
9873  disp->_window_x = disp->_window_y = 0;
9874  disp->set_button().set_key(0).set_key(0,false)._is_closed = true;
9875  ReleaseMutex(disp->_mutex);
9876  ShowWindow(disp->_window,SW_HIDE);
9877  disp->_is_event = true;
9878  SetEvent(cimg::Win32_attr().wait_event);
9879  return 0;
9880  case WM_SIZE : {
9881  while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}
9882  WaitForSingleObject(disp->_mutex,INFINITE);
9883  const unsigned int nw = LOWORD(lParam),nh = HIWORD(lParam);
9884  if (nw && nh && (nw!=disp->_width || nh!=disp->_height)) {
9885  disp->_window_width = nw;
9886  disp->_window_height = nh;
9887  disp->_mouse_x = disp->_mouse_y = -1;
9888  disp->_is_resized = disp->_is_event = true;
9889  SetEvent(cimg::Win32_attr().wait_event);
9890  }
9891  ReleaseMutex(disp->_mutex);
9892  } break;
9893  case WM_MOVE : {
9894  while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}
9895  WaitForSingleObject(disp->_mutex,INFINITE);
9896  const int nx = (int)(short)(LOWORD(lParam)), ny = (int)(short)(HIWORD(lParam));
9897  if (nx!=disp->_window_x || ny!=disp->_window_y) {
9898  disp->_window_x = nx;
9899  disp->_window_y = ny;
9900  disp->_is_moved = disp->_is_event = true;
9901  SetEvent(cimg::Win32_attr().wait_event);
9902  }
9903  ReleaseMutex(disp->_mutex);
9904  } break;
9905  case WM_PAINT :
9906  disp->paint();
9907  cimg::mutex(15);
9908  if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0);
9909  cimg::mutex(15,0);
9910  break;
9911  case WM_ERASEBKGND :
9912  // return 0;
9913  break;
9914  case WM_KEYDOWN :
9915  disp->set_key((unsigned int)wParam);
9916  SetEvent(cimg::Win32_attr().wait_event);
9917  break;
9918  case WM_KEYUP :
9919  disp->set_key((unsigned int)wParam,false);
9920  SetEvent(cimg::Win32_attr().wait_event);
9921  break;
9922  case WM_MOUSEMOVE : {
9923  while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE)) {}
9924  disp->_mouse_x = LOWORD(lParam);
9925  disp->_mouse_y = HIWORD(lParam);
9926 #if (_WIN32_WINNT>=0x0400) && !defined(NOTRACKMOUSEEVENT)
9927  if (!disp->_is_mouse_tracked) {
9928  TRACKMOUSEEVENT tme;
9929  tme.cbSize = sizeof(TRACKMOUSEEVENT);
9930  tme.dwFlags = TME_LEAVE;
9931  tme.hwndTrack = disp->_window;
9932  if (TrackMouseEvent(&tme)) disp->_is_mouse_tracked = true;
9933  }
9934 #endif
9935  if (disp->_mouse_x<0 || disp->_mouse_y<0 || disp->_mouse_x>=disp->width() || disp->_mouse_y>=disp->height())
9936  disp->_mouse_x = disp->_mouse_y = -1;
9937  disp->_is_event = true;
9938  SetEvent(cimg::Win32_attr().wait_event);
9939  cimg::mutex(15);
9940  if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0);
9941  cimg::mutex(15,0);
9942  } break;
9943  case WM_MOUSELEAVE : {
9944  disp->_mouse_x = disp->_mouse_y = -1;
9945  disp->_is_mouse_tracked = false;
9946  cimg::mutex(15);
9947  while (ShowCursor(TRUE)<0) {}
9948  cimg::mutex(15,0);
9949  } break;
9950  case WM_LBUTTONDOWN :
9951  disp->set_button(1);
9952  SetEvent(cimg::Win32_attr().wait_event);
9953  break;
9954  case WM_RBUTTONDOWN :
9955  disp->set_button(2);
9956  SetEvent(cimg::Win32_attr().wait_event);
9957  break;
9958  case WM_MBUTTONDOWN :
9959  disp->set_button(3);
9960  SetEvent(cimg::Win32_attr().wait_event);
9961  break;
9962  case WM_LBUTTONUP :
9963  disp->set_button(1,false);
9964  SetEvent(cimg::Win32_attr().wait_event);
9965  break;
9966  case WM_RBUTTONUP :
9967  disp->set_button(2,false);
9968  SetEvent(cimg::Win32_attr().wait_event);
9969  break;
9970  case WM_MBUTTONUP :
9971  disp->set_button(3,false);
9972  SetEvent(cimg::Win32_attr().wait_event);
9973  break;
9974  case 0x020A : // WM_MOUSEWHEEL:
9975  disp->set_wheel((int)((short)HIWORD(wParam))/120);
9976  SetEvent(cimg::Win32_attr().wait_event);
9977  }
9978  return DefWindowProc(window,msg,wParam,lParam);
9979  }
9980 
9981  static DWORD WINAPI _events_thread(void* arg) {
9982  CImgDisplay *const disp = (CImgDisplay*)(((void**)arg)[0]);
9983  const char *const title = (const char*)(((void**)arg)[1]);
9984  MSG msg;
9985  delete[] (void**)arg;
9986  disp->_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
9987  disp->_bmi.bmiHeader.biWidth = disp->width();
9988  disp->_bmi.bmiHeader.biHeight = -disp->height();
9989  disp->_bmi.bmiHeader.biPlanes = 1;
9990  disp->_bmi.bmiHeader.biBitCount = 32;
9991  disp->_bmi.bmiHeader.biCompression = BI_RGB;
9992  disp->_bmi.bmiHeader.biSizeImage = 0;
9993  disp->_bmi.bmiHeader.biXPelsPerMeter = 1;
9994  disp->_bmi.bmiHeader.biYPelsPerMeter = 1;
9995  disp->_bmi.bmiHeader.biClrUsed = 0;
9996  disp->_bmi.bmiHeader.biClrImportant = 0;
9997  disp->_data = new unsigned int[(size_t)disp->_width*disp->_height];
9998  if (!disp->_is_fullscreen) { // Normal window
9999  RECT rect;
10000  rect.left = rect.top = 0; rect.right = (LONG)disp->_width - 1; rect.bottom = (LONG)disp->_height - 1;
10001  AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
10002  const int
10003  border1 = (int)((rect.right - rect.left + 1 - disp->_width)/2),
10004  border2 = (int)(rect.bottom - rect.top + 1 - disp->_height - border1);
10005  disp->_window = CreateWindowA("MDICLIENT",title?title:" ",
10006  WS_OVERLAPPEDWINDOW | (disp->_is_closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT,
10007  disp->_width + 2*border1, disp->_height + border1 + border2,
10008  0,0,0,&(disp->_ccs));
10009  if (!disp->_is_closed) {
10010  GetWindowRect(disp->_window,&rect);
10011  disp->_window_x = rect.left + border1;
10012  disp->_window_y = rect.top + border2;
10013  } else disp->_window_x = disp->_window_y = 0;
10014  } else { // Fullscreen window
10015  const unsigned int
10016  sx = (unsigned int)screen_width(),
10017  sy = (unsigned int)screen_height();
10018  disp->_window = CreateWindowA("MDICLIENT",title?title:" ",
10019  WS_POPUP | (disp->_is_closed?0:WS_VISIBLE),
10020  (sx - disp->_width)/2,
10021  (sy - disp->_height)/2,
10022  disp->_width,disp->_height,0,0,0,&(disp->_ccs));
10023  disp->_window_x = disp->_window_y = 0;
10024  }
10025  SetForegroundWindow(disp->_window);
10026  disp->_hdc = GetDC(disp->_window);
10027  disp->_window_width = disp->_width;
10028  disp->_window_height = disp->_height;
10029  disp->flush();
10030 #ifdef _WIN64
10031  SetWindowLongPtr(disp->_window,GWLP_USERDATA,(LONG_PTR)disp);
10032  SetWindowLongPtr(disp->_window,GWLP_WNDPROC,(LONG_PTR)_handle_events);
10033 #else
10034  SetWindowLong(disp->_window,GWL_USERDATA,(LONG)disp);
10035  SetWindowLong(disp->_window,GWL_WNDPROC,(LONG)_handle_events);
10036 #endif
10037  SetEvent(disp->_is_created);
10038  while (GetMessage(&msg,0,0,0)) DispatchMessage(&msg);
10039  return 0;
10040  }
10041 
10042  CImgDisplay& _update_window_pos() {
10043  if (_is_closed) _window_x = _window_y = -1;
10044  else {
10045  RECT rect;
10046  rect.left = rect.top = 0; rect.right = (LONG)_width - 1; rect.bottom = (LONG)_height - 1;
10047  AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
10048  const int
10049  border1 = (int)((rect.right - rect.left + 1 - _width)/2),
10050  border2 = (int)(rect.bottom - rect.top + 1 - _height - border1);
10051  GetWindowRect(_window,&rect);
10052  _window_x = rect.left + border1;
10053  _window_y = rect.top + border2;
10054  }
10055  return *this;
10056  }
10057 
10058  void _init_fullscreen() {
10059  _background_window = 0;
10060  if (!_is_fullscreen || _is_closed) _curr_mode.dmSize = 0;
10061  else {
10062  DEVMODE mode;
10063  unsigned int imode = 0, ibest = 0, bestbpp = 0, bw = ~0U, bh = ~0U;
10064  for (mode.dmSize = sizeof(DEVMODE), mode.dmDriverExtra = 0; EnumDisplaySettings(0,imode,&mode); ++imode) {
10065  const unsigned int nw = mode.dmPelsWidth, nh = mode.dmPelsHeight;
10066  if (nw>=_width && nh>=_height && mode.dmBitsPerPel>=bestbpp && nw<=bw && nh<=bh) {
10067  bestbpp = mode.dmBitsPerPel;
10068  ibest = imode;
10069  bw = nw; bh = nh;
10070  }
10071  }
10072  if (bestbpp) {
10073  _curr_mode.dmSize = sizeof(DEVMODE); _curr_mode.dmDriverExtra = 0;
10074  EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&_curr_mode);
10075  EnumDisplaySettings(0,ibest,&mode);
10076  ChangeDisplaySettings(&mode,0);
10077  } else _curr_mode.dmSize = 0;
10078 
10079  const unsigned int
10080  sx = (unsigned int)screen_width(),
10081  sy = (unsigned int)screen_height();
10082  if (sx!=_width || sy!=_height) {
10083  CLIENTCREATESTRUCT background_ccs;
10084  _background_window = CreateWindowA("MDICLIENT","",WS_POPUP | WS_VISIBLE, 0,0,sx,sy,0,0,0,&background_ccs);
10085  SetForegroundWindow(_background_window);
10086  }
10087  }
10088  }
10089 
10090  void _desinit_fullscreen() {
10091  if (!_is_fullscreen) return;
10092  if (_background_window) DestroyWindow(_background_window);
10093  _background_window = 0;
10094  if (_curr_mode.dmSize) ChangeDisplaySettings(&_curr_mode,0);
10095  _is_fullscreen = false;
10096  }
10097 
10098  CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *const ptitle=0,
10099  const unsigned int normalization_type=3,
10100  const bool fullscreen_flag=false, const bool closed_flag=false) {
10101 
10102  // Allocate space for window title
10103  const char *const nptitle = ptitle?ptitle:"";
10104  const unsigned int s = (unsigned int)std::strlen(nptitle) + 1;
10105  char *const tmp_title = s?new char[s]:0;
10106  if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char));
10107 
10108  // Destroy previous window if existing
10109  if (!is_empty()) assign();
10110 
10111  // Set display variables
10112  _width = std::min(dimw,(unsigned int)screen_width());
10113  _height = std::min(dimh,(unsigned int)screen_height());
10114  _normalization = normalization_type<4?normalization_type:3;
10115  _is_fullscreen = fullscreen_flag;
10116  _window_x = _window_y = 0;
10117  _is_closed = closed_flag;
10118  _is_cursor_visible = true;
10119  _is_mouse_tracked = false;
10120  _title = tmp_title;
10121  flush();
10122  if (_is_fullscreen) _init_fullscreen();
10123 
10124  // Create event thread
10125  void *const arg = (void*)(new void*[2]);
10126  ((void**)arg)[0] = (void*)this;
10127  ((void**)arg)[1] = (void*)_title;
10128  _mutex = CreateMutex(0,FALSE,0);
10129  _is_created = CreateEvent(0,FALSE,FALSE,0);
10130  _thread = CreateThread(0,0,_events_thread,arg,0,0);
10131  WaitForSingleObject(_is_created,INFINITE);
10132  return *this;
10133  }
10134 
10135  CImgDisplay& assign() {
10136  if (is_empty()) return flush();
10137  DestroyWindow(_window);
10138  TerminateThread(_thread,0);
10139  delete[] _data;
10140  delete[] _title;
10141  _data = 0;
10142  _title = 0;
10143  if (_is_fullscreen) _desinit_fullscreen();
10144  _width = _height = _normalization = _window_width = _window_height = 0;
10145  _window_x = _window_y = 0;
10146  _is_fullscreen = false;
10147  _is_closed = true;
10148  _min = _max = 0;
10149  _title = 0;
10150  flush();
10151  return *this;
10152  }
10153 
10154  CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *const title=0,
10155  const unsigned int normalization_type=3,
10156  const bool fullscreen_flag=false, const bool closed_flag=false) {
10157  if (!dimw || !dimh) return assign();
10158  _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
10159  _min = _max = 0;
10160  std::memset(_data,0,sizeof(unsigned int)*_width*_height);
10161  return paint();
10162  }
10163 
10164  template<typename T>
10165  CImgDisplay& assign(const CImg<T>& img, const char *const title=0,
10166  const unsigned int normalization_type=3,
10167  const bool fullscreen_flag=false, const bool closed_flag=false) {
10168  if (!img) return assign();
10169  CImg<T> tmp;
10170  const CImg<T>& nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2,
10171  (img._height - 1)/2,
10172  (img._depth - 1)/2));
10173  _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag);
10174  if (_normalization==2) _min = (float)nimg.min_max(_max);
10175  return display(nimg);
10176  }
10177 
10178  template<typename T>
10179  CImgDisplay& assign(const CImgList<T>& list, const char *const title=0,
10180  const unsigned int normalization_type=3,
10181  const bool fullscreen_flag=false, const bool closed_flag=false) {
10182  if (!list) return assign();
10183  CImg<T> tmp;
10184  const CImg<T> img = list>'x', &nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2,
10185  (img._height - 1)/2,
10186  (img._depth - 1)/2));
10187  _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag);
10188  if (_normalization==2) _min = (float)nimg.min_max(_max);
10189  return display(nimg);
10190  }
10191 
10192  CImgDisplay& assign(const CImgDisplay& disp) {
10193  if (!disp) return assign();
10194  _assign(disp._width,disp._height,disp._title,disp._normalization,disp._is_fullscreen,disp._is_closed);
10195  std::memcpy(_data,disp._data,sizeof(unsigned int)*_width*_height);
10196  return paint();
10197  }
10198 
10199  CImgDisplay& resize(const int nwidth, const int nheight, const bool force_redraw=true) {
10200  if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
10201  if (is_empty()) return assign(nwidth,nheight);
10202  const unsigned int
10203  tmpdimx = (nwidth>0)?nwidth:(-nwidth*_width/100),
10204  tmpdimy = (nheight>0)?nheight:(-nheight*_height/100),
10205  dimx = tmpdimx?tmpdimx:1,
10206  dimy = tmpdimy?tmpdimy:1;
10207  if (_width!=dimx || _height!=dimy || _window_width!=dimx || _window_height!=dimy) {
10208  if (_window_width!=dimx || _window_height!=dimy) {
10209  RECT rect; rect.left = rect.top = 0; rect.right = (LONG)dimx - 1; rect.bottom = (LONG)dimy - 1;
10210  AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
10211  const int cwidth = rect.right - rect.left + 1, cheight = rect.bottom - rect.top + 1;
10212  SetWindowPos(_window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);
10213  }
10214  if (_width!=dimx || _height!=dimy) {
10215  unsigned int *const ndata = new unsigned int[dimx*dimy];
10216  if (force_redraw) _render_resize(_data,_width,_height,ndata,dimx,dimy);
10217  else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
10218  delete[] _data;
10219  _data = ndata;
10220  _bmi.bmiHeader.biWidth = (LONG)dimx;
10221  _bmi.bmiHeader.biHeight = -(int)dimy;
10222  _width = dimx;
10223  _height = dimy;
10224  }
10225  _window_width = dimx; _window_height = dimy;
10226  show();
10227  }
10228  _is_resized = false;
10229  if (_is_fullscreen) move((screen_width() - width())/2,(screen_height() - height())/2);
10230  if (force_redraw) return paint();
10231  return *this;
10232  }
10233 
10234  CImgDisplay& toggle_fullscreen(const bool force_redraw=true) {
10235  if (is_empty()) return *this;
10236  if (force_redraw) {
10237  const cimg_ulong buf_size = (cimg_ulong)_width*_height*4;
10238  void *odata = std::malloc(buf_size);
10239  if (odata) {
10240  std::memcpy(odata,_data,buf_size);
10241  assign(_width,_height,_title,_normalization,!_is_fullscreen,false);
10242  std::memcpy(_data,odata,buf_size);
10243  std::free(odata);
10244  }
10245  return paint();
10246  }
10247  return assign(_width,_height,_title,_normalization,!_is_fullscreen,false);
10248  }
10249 
10250  CImgDisplay& show() {
10251  if (is_empty() || !_is_closed) return *this;
10252  _is_closed = false;
10253  if (_is_fullscreen) _init_fullscreen();
10254  ShowWindow(_window,SW_SHOW);
10255  _update_window_pos();
10256  return paint();
10257  }
10258 
10259  CImgDisplay& close() {
10260  if (is_empty() || _is_closed) return *this;
10261  _is_closed = true;
10262  if (_is_fullscreen) _desinit_fullscreen();
10263  ShowWindow(_window,SW_HIDE);
10264  _window_x = _window_y = 0;
10265  return *this;
10266  }
10267 
10268  CImgDisplay& move(const int posx, const int posy) {
10269  if (is_empty()) return *this;
10270  if (_window_x!=posx || _window_y!=posy) {
10271  if (!_is_fullscreen) {
10272  RECT rect;
10273  rect.left = rect.top = 0; rect.right = (LONG)_window_width - 1; rect.bottom = (LONG)_window_height - 1;
10274  AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
10275  const int
10276  border1 = (int)((rect.right - rect.left + 1 -_width)/2),
10277  border2 = (int)(rect.bottom - rect.top + 1 - _height - border1);
10278  SetWindowPos(_window,0,posx - border1,posy - border2,0,0,SWP_NOSIZE | SWP_NOZORDER);
10279  } else SetWindowPos(_window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER);
10280  _window_x = posx;
10281  _window_y = posy;
10282  show();
10283  }
10284  _is_moved = false;
10285  return *this;
10286  }
10287 
10288  CImgDisplay& show_mouse() {
10289  if (is_empty()) return *this;
10290  _is_cursor_visible = true;
10291  return *this;
10292  }
10293 
10294  CImgDisplay& hide_mouse() {
10295  if (is_empty()) return *this;
10296  _is_cursor_visible = false;
10297  return *this;
10298  }
10299 
10300  CImgDisplay& set_mouse(const int posx, const int posy) {
10301  if (is_empty() || _is_closed || posx<0 || posy<0) return *this;
10302  _update_window_pos();
10303  const int res = (int)SetCursorPos(_window_x + posx,_window_y + posy);
10304  if (res) { _mouse_x = posx; _mouse_y = posy; }
10305  return *this;
10306  }
10307 
10308  CImgDisplay& set_title(const char *const format, ...) {
10309  if (is_empty()) return *this;
10310  char *const tmp = new char[1024];
10311  va_list ap;
10312  va_start(ap, format);
10313  cimg_vsnprintf(tmp,1024,format,ap);
10314  va_end(ap);
10315  if (!std::strcmp(_title,tmp)) { delete[] tmp; return *this; }
10316  delete[] _title;
10317  const unsigned int s = (unsigned int)std::strlen(tmp) + 1;
10318  _title = new char[s];
10319  std::memcpy(_title,tmp,s*sizeof(char));
10320  SetWindowTextA(_window, tmp);
10321  delete[] tmp;
10322  return *this;
10323  }
10324 
10325  template<typename T>
10326  CImgDisplay& display(const CImg<T>& img) {
10327  if (!img)
10328  throw CImgArgumentException(_cimgdisplay_instance
10329  "display(): Empty specified image.",
10330  cimgdisplay_instance);
10331  if (is_empty()) return assign(img);
10332  return render(img).paint();
10333  }
10334 
10335  CImgDisplay& paint() {
10336  if (_is_closed) return *this;
10337  WaitForSingleObject(_mutex,INFINITE);
10338  SetDIBitsToDevice(_hdc,0,0,_width,_height,0,0,0,_height,_data,&_bmi,DIB_RGB_COLORS);
10339  ReleaseMutex(_mutex);
10340  return *this;
10341  }
10342 
10343  template<typename T>
10344  CImgDisplay& render(const CImg<T>& img) {
10345  if (!img)
10346  throw CImgArgumentException(_cimgdisplay_instance
10347  "render(): Empty specified image.",
10348  cimgdisplay_instance);
10349 
10350  if (is_empty()) return *this;
10351  if (img._depth!=1) return render(img.get_projections2d((img._width - 1)/2,(img._height - 1)/2,
10352  (img._depth - 1)/2));
10353 
10354  const T
10355  *data1 = img._data,
10356  *data2 = (img._spectrum>=2)?img.data(0,0,0,1):data1,
10357  *data3 = (img._spectrum>=3)?img.data(0,0,0,2):data1;
10358 
10359  WaitForSingleObject(_mutex,INFINITE);
10360  unsigned int
10361  *const ndata = (img._width==_width && img._height==_height)?_data:
10362  new unsigned int[(size_t)img._width*img._height],
10363  *ptrd = ndata;
10364 
10365  if (!_normalization || (_normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
10366  _min = _max = 0;
10367  switch (img._spectrum) {
10368  case 1 : {
10369  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
10370  const unsigned char val = (unsigned char)*(data1++);
10371  *(ptrd++) = (unsigned int)((val<<16) | (val<<8) | val);
10372  }
10373  } break;
10374  case 2 : {
10375  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
10376  const unsigned char
10377  R = (unsigned char)*(data1++),
10378  G = (unsigned char)*(data2++);
10379  *(ptrd++) = (unsigned int)((R<<16) | (G<<8));
10380  }
10381  } break;
10382  default : {
10383  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
10384  const unsigned char
10385  R = (unsigned char)*(data1++),
10386  G = (unsigned char)*(data2++),
10387  B = (unsigned char)*(data3++);
10388  *(ptrd++) = (unsigned int)((R<<16) | (G<<8) | B);
10389  }
10390  }
10391  }
10392  } else {
10393  if (_normalization==3) {
10394  if (cimg::type<T>::is_float()) _min = (float)img.min_max(_max);
10395  else { _min = (float)cimg::type<T>::min(); _max = (float)cimg::type<T>::max(); }
10396  } else if ((_min>_max) || _normalization==1) _min = (float)img.min_max(_max);
10397  const float delta = _max - _min, mm = 255/(delta?delta:1.0f);
10398  switch (img._spectrum) {
10399  case 1 : {
10400  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
10401  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);
10402  *(ptrd++) = (unsigned int)((val<<16) | (val<<8) | val);
10403  }
10404  } break;
10405  case 2 : {
10406  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
10407  const unsigned char
10408  R = (unsigned char)((*(data1++) - _min)*mm),
10409  G = (unsigned char)((*(data2++) - _min)*mm);
10410  *(ptrd++) = (unsigned int)((R<<16) | (G<<8));
10411  }
10412  } break;
10413  default : {
10414  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
10415  const unsigned char
10416  R = (unsigned char)((*(data1++) - _min)*mm),
10417  G = (unsigned char)((*(data2++) - _min)*mm),
10418  B = (unsigned char)((*(data3++) - _min)*mm);
10419  *(ptrd++) = (unsigned int)((R<<16) | (G<<8) | B);
10420  }
10421  }
10422  }
10423  }
10424  if (ndata!=_data) { _render_resize(ndata,img._width,img._height,_data,_width,_height); delete[] ndata; }
10425  ReleaseMutex(_mutex);
10426  return *this;
10427  }
10428 
10429  template<typename T>
10430  static void screenshot(const int x0, const int y0, const int x1, const int y1, CImg<T>& img) {
10431  img.assign();
10432  HDC hScreen = GetDC(GetDesktopWindow());
10433  if (hScreen) {
10434  const int
10435  width = GetDeviceCaps(hScreen,HORZRES),
10436  height = GetDeviceCaps(hScreen,VERTRES);
10437  int _x0 = x0, _y0 = y0, _x1 = x1, _y1 = y1;
10438  if (_x0>_x1) cimg::swap(_x0,_x1);
10439  if (_y0>_y1) cimg::swap(_y0,_y1);
10440  if (_x1>=0 && _x0<width && _y1>=0 && _y0<height) {
10441  _x0 = std::max(_x0,0);
10442  _y0 = std::max(_y0,0);
10443  _x1 = std::min(_x1,width - 1);
10444  _y1 = std::min(_y1,height - 1);
10445  const int bw = _x1 - _x0 + 1, bh = _y1 - _y0 + 1;
10446  HDC hdcMem = CreateCompatibleDC(hScreen);
10447  if (hdcMem) {
10448  HBITMAP hBitmap = CreateCompatibleBitmap(hScreen,bw,bh);
10449  if (hBitmap) {
10450  HGDIOBJ hOld = SelectObject(hdcMem,hBitmap);
10451  if (hOld && BitBlt(hdcMem,0,0,bw,bh,hScreen,_x0,_y0,SRCCOPY) && SelectObject(hdcMem,hOld)) {
10452  BITMAPINFOHEADER bmi;
10453  bmi.biSize = sizeof(BITMAPINFOHEADER);
10454  bmi.biWidth = bw;
10455  bmi.biHeight = -bh;
10456  bmi.biPlanes = 1;
10457  bmi.biBitCount = 32;
10458  bmi.biCompression = BI_RGB;
10459  bmi.biSizeImage = 0;
10460  bmi.biXPelsPerMeter = bmi.biYPelsPerMeter = 0;
10461  bmi.biClrUsed = bmi.biClrImportant = 0;
10462  unsigned char *buf = new unsigned char[4*bw*bh];
10463  if (GetDIBits(hdcMem,hBitmap,0,bh,buf,(BITMAPINFO*)&bmi,DIB_RGB_COLORS)) {
10464  img.assign(bw,bh,1,3);
10465  const unsigned char *ptrs = buf;
10466  T *pR = img.data(0,0,0,0), *pG = img.data(0,0,0,1), *pB = img.data(0,0,0,2);
10467  cimg_forXY(img,x,y) {
10468  *(pR++) = (T)ptrs[2];
10469  *(pG++) = (T)ptrs[1];
10470  *(pB++) = (T)ptrs[0];
10471  ptrs+=4;
10472  }
10473  }
10474  delete[] buf;
10475  }
10476  DeleteObject(hBitmap);
10477  }
10478  DeleteDC(hdcMem);
10479  }
10480  }
10481  ReleaseDC(GetDesktopWindow(),hScreen);
10482  }
10483  if (img.is_empty())
10484  throw CImgDisplayException("CImgDisplay::screenshot(): Failed to take screenshot "
10485  "with coordinates (%d,%d)-(%d,%d).",
10486  x0,y0,x1,y1);
10487  }
10488 
10489  template<typename T>
10490  const CImgDisplay& snapshot(CImg<T>& img) const {
10491  if (is_empty()) { img.assign(); return *this; }
10492  const unsigned int *ptrs = _data;
10493  img.assign(_width,_height,1,3);
10494  T
10495  *data1 = img.data(0,0,0,0),
10496  *data2 = img.data(0,0,0,1),
10497  *data3 = img.data(0,0,0,2);
10498  for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
10499  const unsigned int val = *(ptrs++);
10500  *(data1++) = (T)(unsigned char)(val>>16);
10501  *(data2++) = (T)(unsigned char)((val>>8)&0xFF);
10502  *(data3++) = (T)(unsigned char)(val&0xFF);
10503  }
10504  return *this;
10505  }
10506 #endif
10507 
10509  };
10510 
10511  /*
10512  #--------------------------------------
10513  #
10514  #
10515  #
10516  # Definition of the CImg<T> structure
10517  #
10518  #
10519  #
10520  #--------------------------------------
10521  */
10522 
10524 
10614  template<typename T>
10615  struct CImg {
10616 
10617  unsigned int _width, _height, _depth, _spectrum;
10618  bool _is_shared;
10619  T *_data;
10620 
10622 
10635  typedef T* iterator;
10636 
10638 
10652  typedef const T* const_iterator;
10653 
10655 
10662  typedef T value_type;
10663 
10664  // Define common types related to template type T.
10665  typedef typename cimg::superset<T,bool>::type Tbool;
10666  typedef typename cimg::superset<T,unsigned char>::type Tuchar;
10667  typedef typename cimg::superset<T,char>::type Tchar;
10668  typedef typename cimg::superset<T,unsigned short>::type Tushort;
10669  typedef typename cimg::superset<T,short>::type Tshort;
10670  typedef typename cimg::superset<T,unsigned int>::type Tuint;
10671  typedef typename cimg::superset<T,int>::type Tint;
10672  typedef typename cimg::superset<T,cimg_ulong>::type Tulong;
10673  typedef typename cimg::superset<T,cimg_long>::type Tlong;
10674  typedef typename cimg::superset<T,float>::type Tfloat;
10675  typedef typename cimg::superset<T,double>::type Tdouble;
10676  typedef typename cimg::last<T,bool>::type boolT;
10677  typedef typename cimg::last<T,unsigned char>::type ucharT;
10678  typedef typename cimg::last<T,char>::type charT;
10679  typedef typename cimg::last<T,unsigned short>::type ushortT;
10680  typedef typename cimg::last<T,short>::type shortT;
10681  typedef typename cimg::last<T,unsigned int>::type uintT;
10682  typedef typename cimg::last<T,int>::type intT;
10683  typedef typename cimg::last<T,cimg_ulong>::type ulongT;
10684  typedef typename cimg::last<T,cimg_long>::type longT;
10685  typedef typename cimg::last<T,cimg_uint64>::type uint64T;
10686  typedef typename cimg::last<T,cimg_int64>::type int64T;
10687  typedef typename cimg::last<T,float>::type floatT;
10688  typedef typename cimg::last<T,double>::type doubleT;
10689 
10691  //---------------------------
10692  //
10694 
10695  //---------------------------
10696 #ifdef cimg_plugin
10697 #include cimg_plugin
10698 #endif
10699 #ifdef cimg_plugin1
10700 #include cimg_plugin1
10701 #endif
10702 #ifdef cimg_plugin2
10703 #include cimg_plugin2
10704 #endif
10705 #ifdef cimg_plugin3
10706 #include cimg_plugin3
10707 #endif
10708 #ifdef cimg_plugin4
10709 #include cimg_plugin4
10710 #endif
10711 #ifdef cimg_plugin5
10712 #include cimg_plugin5
10713 #endif
10714 #ifdef cimg_plugin6
10715 #include cimg_plugin6
10716 #endif
10717 #ifdef cimg_plugin7
10718 #include cimg_plugin7
10719 #endif
10720 #ifdef cimg_plugin8
10721 #include cimg_plugin8
10722 #endif
10723 
10725  //---------------------------------------------------------
10726  //
10728 
10729  //---------------------------------------------------------
10730 
10732 
10741  ~CImg() {
10742  if (!_is_shared) delete[] _data;
10743  }
10744 
10746 
10762  CImg():_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {}
10763 
10765 
10787  explicit CImg(const unsigned int size_x, const unsigned int size_y=1,
10788  const unsigned int size_z=1, const unsigned int size_c=1):
10789  _is_shared(false) {
10790  size_t siz = (size_t)size_x*size_y*size_z*size_c;
10791  if (siz) {
10792  _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;
10793  try { _data = new T[siz]; } catch (...) {
10794  _width = _height = _depth = _spectrum = 0; _data = 0;
10795  throw CImgInstanceException(_cimg_instance
10796  "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
10797  cimg_instance,
10798  cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),
10799  size_x,size_y,size_z,size_c);
10800  }
10801  } else { _width = _height = _depth = _spectrum = 0; _data = 0; }
10802  }
10803 
10805 
10819  CImg(const unsigned int size_x, const unsigned int size_y,
10820  const unsigned int size_z, const unsigned int size_c, const T& value):
10821  _is_shared(false) {
10822  const size_t siz = (size_t)size_x*size_y*size_z*size_c;
10823  if (siz) {
10824  _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;
10825  try { _data = new T[siz]; } catch (...) {
10826  _width = _height = _depth = _spectrum = 0; _data = 0;
10827  throw CImgInstanceException(_cimg_instance
10828  "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
10829  cimg_instance,
10830  cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),
10831  size_x,size_y,size_z,size_c);
10832  }
10833  fill(value);
10834  } else { _width = _height = _depth = _spectrum = 0; _data = 0; }
10835  }
10836 
10838 
10865  CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c,
10866  const int value0, const int value1, ...):
10867  _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
10868 #define _CImg_stdarg(img,a0,a1,N,t) { \
10869  size_t _siz = (size_t)N; \
10870  if (_siz--) { \
10871  va_list ap; \
10872  va_start(ap,a1); \
10873  T *ptrd = (img)._data; \
10874  *(ptrd++) = (T)a0; \
10875  if (_siz--) { \
10876  *(ptrd++) = (T)a1; \
10877  for ( ; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \
10878  } \
10879  va_end(ap); \
10880  } \
10881  }
10882  assign(size_x,size_y,size_z,size_c);
10883  _CImg_stdarg(*this,value0,value1,(size_t)size_x*size_y*size_z*size_c,int);
10884  }
10885 
10886 #if cimg_use_cpp11==1
10887 
10912  template<typename t>
10913  CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c,
10914  const std::initializer_list<t> values,
10915  const bool repeat_values=true):
10916  _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
10917 #define _cimg_constructor_cpp11(repeat_values) \
10918  auto it = values.begin(); \
10919  size_t siz = size(); \
10920  if (repeat_values) for (T *ptrd = _data; siz--; ) { \
10921  *(ptrd++) = (T)(*(it++)); if (it==values.end()) it = values.begin(); } \
10922  else { siz = std::min(siz,values.size()); for (T *ptrd = _data; siz--; ) *(ptrd++) = (T)(*(it++)); }
10923  assign(size_x,size_y,size_z,size_c);
10924  _cimg_constructor_cpp11(repeat_values);
10925  }
10926 
10927  template<typename t>
10928  CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z,
10929  std::initializer_list<t> values,
10930  const bool repeat_values=true):
10931  _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
10932  assign(size_x,size_y,size_z);
10933  _cimg_constructor_cpp11(repeat_values);
10934  }
10935 
10936  template<typename t>
10937  CImg(const unsigned int size_x, const unsigned int size_y,
10938  std::initializer_list<t> values,
10939  const bool repeat_values=true):
10940  _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
10941  assign(size_x,size_y);
10942  _cimg_constructor_cpp11(repeat_values);
10943  }
10944 
10945  template<typename t>
10946  CImg(const unsigned int size_x,
10947  std::initializer_list<t> values,
10948  const bool repeat_values=true):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
10949  assign(size_x);
10950  _cimg_constructor_cpp11(repeat_values);
10951  }
10952 
10954 
10970  template<typename t>
10971  CImg(const std::initializer_list<t> values):
10972  _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
10973  assign(values.size(),1,1,1);
10974  auto it = values.begin();
10975  unsigned int siz = _width;
10976  for (T *ptrd = _data; siz--; ) *(ptrd++) = (T)(*(it++));
10977  }
10978 
10979  template<typename t>
10980  CImg<T> & operator=(std::initializer_list<t> values) {
10981  _cimg_constructor_cpp11(siz>values.size());
10982  return *this;
10983  }
10984 #endif
10985 
10987 
11008  CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c,
11009  const double value0, const double value1, ...):
11010  _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
11011  assign(size_x,size_y,size_z,size_c);
11012  _CImg_stdarg(*this,value0,value1,(size_t)size_x*size_y*size_z*size_c,double);
11013  }
11014 
11016 
11045  CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c,
11046  const char *const values, const bool repeat_values):_is_shared(false) {
11047  const size_t siz = (size_t)size_x*size_y*size_z*size_c;
11048  if (siz) {
11049  _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;
11050  try { _data = new T[siz]; } catch (...) {
11051  _width = _height = _depth = _spectrum = 0; _data = 0;
11052  throw CImgInstanceException(_cimg_instance
11053  "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
11054  cimg_instance,
11055  cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),
11056  size_x,size_y,size_z,size_c);
11057  }
11058  fill(values,repeat_values);
11059  } else { _width = _height = _depth = _spectrum = 0; _data = 0; }
11060  }
11061 
11063 
11092  template<typename t>
11093  CImg(const t *const values, const unsigned int size_x, const unsigned int size_y=1,
11094  const unsigned int size_z=1, const unsigned int size_c=1, const bool is_shared=false):_is_shared(false) {
11095  if (is_shared) {
11096  _width = _height = _depth = _spectrum = 0; _data = 0;
11097  throw CImgArgumentException(_cimg_instance
11098  "CImg(): Invalid construction request of a (%u,%u,%u,%u) shared instance "
11099  "from a (%s*) buffer (pixel types are different).",
11100  cimg_instance,
11101  size_x,size_y,size_z,size_c,CImg<t>::pixel_type());
11102  }
11103  const size_t siz = (size_t)size_x*size_y*size_z*size_c;
11104  if (values && siz) {
11105  _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;
11106  try { _data = new T[siz]; } catch (...) {
11107  _width = _height = _depth = _spectrum = 0; _data = 0;
11108  throw CImgInstanceException(_cimg_instance
11109  "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
11110  cimg_instance,
11111  cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),
11112  size_x,size_y,size_z,size_c);
11113 
11114  }
11115  const t *ptrs = values; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++);
11116  } else { _width = _height = _depth = _spectrum = 0; _data = 0; }
11117  }
11118 
11120  CImg(const T *const values, const unsigned int size_x, const unsigned int size_y=1,
11121  const unsigned int size_z=1, const unsigned int size_c=1, const bool is_shared=false) {
11122  const size_t siz = (size_t)size_x*size_y*size_z*size_c;
11123  if (values && siz) {
11124  _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; _is_shared = is_shared;
11125  if (_is_shared) _data = const_cast<T*>(values);
11126  else {
11127  try { _data = new T[siz]; } catch (...) {
11128  _width = _height = _depth = _spectrum = 0; _data = 0;
11129  throw CImgInstanceException(_cimg_instance
11130  "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
11131  cimg_instance,
11132  cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),
11133  size_x,size_y,size_z,size_c);
11134  }
11135  std::memcpy(_data,values,siz*sizeof(T));
11136  }
11137  } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; }
11138  }
11139 
11141 
11161  explicit CImg(const char *const filename):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
11162  assign(filename);
11163  }
11164 
11166 
11184  template<typename t>
11185  CImg(const CImg<t>& img):_is_shared(false) {
11186  const size_t siz = (size_t)img.size();
11187  if (img._data && siz) {
11188  _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum;
11189  try { _data = new T[siz]; } catch (...) {
11190  _width = _height = _depth = _spectrum = 0; _data = 0;
11191  throw CImgInstanceException(_cimg_instance
11192  "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
11193  cimg_instance,
11194  cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum),
11195  img._width,img._height,img._depth,img._spectrum);
11196  }
11197  const t *ptrs = img._data; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++);
11198  } else { _width = _height = _depth = _spectrum = 0; _data = 0; }
11199  }
11200 
11202  CImg(const CImg<T>& img) {
11203  const size_t siz = (size_t)img.size();
11204  if (img._data && siz) {
11205  _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum;
11206  _is_shared = img._is_shared;
11207  if (_is_shared) _data = const_cast<T*>(img._data);
11208  else {
11209  try { _data = new T[siz]; } catch (...) {
11210  _width = _height = _depth = _spectrum = 0; _data = 0;
11211  throw CImgInstanceException(_cimg_instance
11212  "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
11213  cimg_instance,
11214  cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum),
11215  img._width,img._height,img._depth,img._spectrum);
11216 
11217  }
11218  std::memcpy(_data,img._data,siz*sizeof(T));
11219  }
11220  } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; }
11221  }
11222 
11224 
11238  template<typename t>
11239  CImg(const CImg<t>& img, const bool is_shared):_is_shared(false) {
11240  if (is_shared) {
11241  _width = _height = _depth = _spectrum = 0; _data = 0;
11242  throw CImgArgumentException(_cimg_instance
11243  "CImg(): Invalid construction request of a shared instance from a "
11244  "CImg<%s> image (%u,%u,%u,%u,%p) (pixel types are different).",
11245  cimg_instance,
11246  CImg<t>::pixel_type(),img._width,img._height,img._depth,img._spectrum,img._data);
11247  }
11248  const size_t siz = (size_t)img.size();
11249  if (img._data && siz) {
11250  _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum;
11251  try { _data = new T[siz]; } catch (...) {
11252  _width = _height = _depth = _spectrum = 0; _data = 0;
11253  throw CImgInstanceException(_cimg_instance
11254  "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
11255  cimg_instance,
11256  cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum),
11257  img._width,img._height,img._depth,img._spectrum);
11258  }
11259  const t *ptrs = img._data; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++);
11260  } else { _width = _height = _depth = _spectrum = 0; _data = 0; }
11261  }
11262 
11264  CImg(const CImg<T>& img, const bool is_shared) {
11265  const size_t siz = (size_t)img.size();
11266  if (img._data && siz) {
11267  _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum;
11268  _is_shared = is_shared;
11269  if (_is_shared) _data = const_cast<T*>(img._data);
11270  else {
11271  try { _data = new T[siz]; } catch (...) {
11272  _width = _height = _depth = _spectrum = 0; _data = 0;
11273  throw CImgInstanceException(_cimg_instance
11274  "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
11275  cimg_instance,
11276  cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum),
11277  img._width,img._height,img._depth,img._spectrum);
11278  }
11279  std::memcpy(_data,img._data,siz*sizeof(T));
11280  }
11281  } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; }
11282  }
11283 
11285 
11304  template<typename t>
11305  CImg(const CImg<t>& img, const char *const dimensions):
11306  _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
11307  assign(img,dimensions);
11308  }
11309 
11311 
11320  template<typename t>
11321  CImg(const CImg<t>& img, const char *const dimensions, const T& value):
11322  _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
11323  assign(img,dimensions).fill(value);
11324  }
11325 
11327 
11336  explicit CImg(const CImgDisplay &disp):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
11337  disp.snapshot(*this);
11338  }
11339 
11340  // Constructor and assignment operator for rvalue references (c++11).
11341  // This avoids an additional image copy for methods returning new images. Can save RAM for big images !
11342 #if cimg_use_cpp11==1
11343  CImg(CImg<T>&& img):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
11344  swap(img);
11345  }
11346  CImg<T>& operator=(CImg<T>&& img) {
11347  if (_is_shared) return assign(img);
11348  return img.swap(*this);
11349  }
11350 #endif
11351 
11353 
11357  if (!_is_shared) delete[] _data;
11358  _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0;
11359  return *this;
11360  }
11361 
11363 
11366  CImg<T>& assign(const unsigned int size_x, const unsigned int size_y=1,
11367  const unsigned int size_z=1, const unsigned int size_c=1) {
11368  const size_t siz = (size_t)size_x*size_y*size_z*size_c;
11369  if (!siz) return assign();
11370  const size_t curr_siz = (size_t)size();
11371  if (siz!=curr_siz) {
11372  if (_is_shared)
11373  throw CImgArgumentException(_cimg_instance
11374  "assign(): Invalid assignement request of shared instance from specified "
11375  "image (%u,%u,%u,%u).",
11376  cimg_instance,
11377  size_x,size_y,size_z,size_c);
11378  else {
11379  delete[] _data;
11380  try { _data = new T[siz]; } catch (...) {
11381  _width = _height = _depth = _spectrum = 0; _data = 0;
11382  throw CImgInstanceException(_cimg_instance
11383  "assign(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
11384  cimg_instance,
11385  cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),
11386  size_x,size_y,size_z,size_c);
11387  }
11388  }
11389  }
11390  _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;
11391  return *this;
11392  }
11393 
11395 
11398  CImg<T>& assign(const unsigned int size_x, const unsigned int size_y,
11399  const unsigned int size_z, const unsigned int size_c, const T& value) {
11400  return assign(size_x,size_y,size_z,size_c).fill(value);
11401  }
11402 
11404 
11407  CImg<T>& assign(const unsigned int size_x, const unsigned int size_y,
11408  const unsigned int size_z, const unsigned int size_c,
11409  const int value0, const int value1, ...) {
11410  assign(size_x,size_y,size_z,size_c);
11411  _CImg_stdarg(*this,value0,value1,(size_t)size_x*size_y*size_z*size_c,int);
11412  return *this;
11413  }
11414 
11416 
11419  CImg<T>& assign(const unsigned int size_x, const unsigned int size_y,
11420  const unsigned int size_z, const unsigned int size_c,
11421  const double value0, const double value1, ...) {
11422  assign(size_x,size_y,size_z,size_c);
11423  _CImg_stdarg(*this,value0,value1,(size_t)size_x*size_y*size_z*size_c,double);
11424  return *this;
11425  }
11426 
11428 
11431  CImg<T>& assign(const unsigned int size_x, const unsigned int size_y,
11432  const unsigned int size_z, const unsigned int size_c,
11433  const char *const values, const bool repeat_values) {
11434  return assign(size_x,size_y,size_z,size_c).fill(values,repeat_values);
11435  }
11436 
11438 
11441  template<typename t>
11442  CImg<T>& assign(const t *const values, const unsigned int size_x, const unsigned int size_y=1,
11443  const unsigned int size_z=1, const unsigned int size_c=1) {
11444  const size_t siz = (size_t)size_x*size_y*size_z*size_c;
11445  if (!values || !siz) return assign();
11446  assign(size_x,size_y,size_z,size_c);
11447  const t *ptrs = values; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++);
11448  return *this;
11449  }
11450 
11452  CImg<T>& assign(const T *const values, const unsigned int size_x, const unsigned int size_y=1,
11453  const unsigned int size_z=1, const unsigned int size_c=1) {
11454  const size_t siz = (size_t)size_x*size_y*size_z*size_c;
11455  if (!values || !siz) return assign();
11456  const size_t curr_siz = (size_t)size();
11457  if (values==_data && siz==curr_siz) return assign(size_x,size_y,size_z,size_c);
11458  if (_is_shared || values + siz<_data || values>=_data + size()) {
11459  assign(size_x,size_y,size_z,size_c);
11460  if (_is_shared) std::memmove(_data,values,siz*sizeof(T));
11461  else std::memcpy(_data,values,siz*sizeof(T));
11462  } else {
11463  T *new_data = 0;
11464  try { new_data = new T[siz]; } catch (...) {
11465  _width = _height = _depth = _spectrum = 0; _data = 0;
11466  throw CImgInstanceException(_cimg_instance
11467  "assign(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
11468  cimg_instance,
11469  cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),
11470  size_x,size_y,size_z,size_c);
11471  }
11472  std::memcpy(new_data,values,siz*sizeof(T));
11473  delete[] _data; _data = new_data; _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;
11474  }
11475  return *this;
11476  }
11477 
11479  template<typename t>
11480  CImg<T>& assign(const t *const values, const unsigned int size_x, const unsigned int size_y,
11481  const unsigned int size_z, const unsigned int size_c, const bool is_shared) {
11482  if (is_shared)
11483  throw CImgArgumentException(_cimg_instance
11484  "assign(): Invalid assignment request of shared instance from (%s*) buffer"
11485  "(pixel types are different).",
11486  cimg_instance,
11488  return assign(values,size_x,size_y,size_z,size_c);
11489  }
11490 
11492  CImg<T>& assign(const T *const values, const unsigned int size_x, const unsigned int size_y,
11493  const unsigned int size_z, const unsigned int size_c, const bool is_shared) {
11494  const size_t siz = (size_t)size_x*size_y*size_z*size_c;
11495  if (!values || !siz) return assign();
11496  if (!is_shared) { if (_is_shared) assign(); assign(values,size_x,size_y,size_z,size_c); }
11497  else {
11498  if (!_is_shared) {
11499  if (values + siz<_data || values>=_data + size()) assign();
11500  else cimg::warn(_cimg_instance
11501  "assign(): Shared image instance has overlapping memory.",
11502  cimg_instance);
11503  }
11504  _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; _is_shared = true;
11505  _data = const_cast<T*>(values);
11506  }
11507  return *this;
11508  }
11509 
11511 
11514  CImg<T>& assign(const char *const filename) {
11515  return load(filename);
11516  }
11517 
11519 
11522  template<typename t>
11523  CImg<T>& assign(const CImg<t>& img) {
11524  return assign(img._data,img._width,img._height,img._depth,img._spectrum);
11525  }
11526 
11528 
11531  template<typename t>
11532  CImg<T>& assign(const CImg<t>& img, const bool is_shared) {
11533  return assign(img._data,img._width,img._height,img._depth,img._spectrum,is_shared);
11534  }
11535 
11537 
11540  template<typename t>
11541  CImg<T>& assign(const CImg<t>& img, const char *const dimensions) {
11542  if (!dimensions || !*dimensions) return assign(img._width,img._height,img._depth,img._spectrum);
11543  unsigned int siz[4] = { 0,1,1,1 }, k = 0;
11544  CImg<charT> item(256);
11545  for (const char *s = dimensions; *s && k<4; ++k) {
11546  if (cimg_sscanf(s,"%255[^0-9%xyzvwhdcXYZVWHDC]",item._data)>0) s+=std::strlen(item);
11547  if (*s) {
11548  unsigned int val = 0; char sep = 0;
11549  if (cimg_sscanf(s,"%u%c",&val,&sep)>0) {
11550  if (sep=='%') siz[k] = val*(k==0?_width:k==1?_height:k==2?_depth:_spectrum)/100;
11551  else siz[k] = val;
11552  while (*s>='0' && *s<='9') ++s;
11553  if (sep=='%') ++s;
11554  } else switch (cimg::lowercase(*s)) {
11555  case 'x' : case 'w' : siz[k] = img._width; ++s; break;
11556  case 'y' : case 'h' : siz[k] = img._height; ++s; break;
11557  case 'z' : case 'd' : siz[k] = img._depth; ++s; break;
11558  case 'c' : case 's' : siz[k] = img._spectrum; ++s; break;
11559  default :
11560  throw CImgArgumentException(_cimg_instance
11561  "assign(): Invalid character '%c' detected in specified dimension string '%s'.",
11562  cimg_instance,
11563  *s,dimensions);
11564  }
11565  }
11566  }
11567  return assign(siz[0],siz[1],siz[2],siz[3]);
11568  }
11569 
11571 
11574  template<typename t>
11575  CImg<T>& assign(const CImg<t>& img, const char *const dimensions, const T& value) {
11576  return assign(img,dimensions).fill(value);
11577  }
11578 
11580 
11583  CImg<T>& assign(const CImgDisplay &disp) {
11584  disp.snapshot(*this);
11585  return *this;
11586  }
11587 
11589 
11595  return assign();
11596  }
11597 
11599 
11614  template<typename t>
11616  img.assign(*this);
11617  assign();
11618  return img;
11619  }
11620 
11623  if (_is_shared || img._is_shared) img.assign(*this);
11624  else swap(img);
11625  assign();
11626  return img;
11627  }
11628 
11630 
11647  template<typename t>
11648  CImgList<t>& move_to(CImgList<t>& list, const unsigned int pos=~0U) {
11649  const unsigned int npos = pos>list._width?list._width:pos;
11650  move_to(list.insert(1,npos)[npos]);
11651  return list;
11652  }
11653 
11655 
11668  cimg::swap(_width,img._width,_height,img._height,_depth,img._depth,_spectrum,img._spectrum);
11669  cimg::swap(_data,img._data);
11670  cimg::swap(_is_shared,img._is_shared);
11671  return img;
11672  }
11673 
11675 
11683  static CImg<T>& empty() {
11684  static CImg<T> _empty;
11685  return _empty.assign();
11686  }
11687 
11689  static const CImg<T>& const_empty() {
11690  static const CImg<T> _empty;
11691  return _empty;
11692  }
11693 
11695  //------------------------------------------
11696  //
11698 
11699  //------------------------------------------
11700 
11702 
11734 #if cimg_verbosity>=3
11735  T& operator()(const unsigned int x, const unsigned int y=0,
11736  const unsigned int z=0, const unsigned int c=0) {
11737  const ulongT off = (ulongT)offset(x,y,z,c);
11738  if (!_data || off>=size()) {
11739  cimg::warn(_cimg_instance
11740  "operator(): Invalid pixel request, at coordinates (%d,%d,%d,%d) [offset=%u].",
11741  cimg_instance,
11742  (int)x,(int)y,(int)z,(int)c,off);
11743  return *_data;
11744  }
11745  else return _data[off];
11746  }
11747 
11749  const T& operator()(const unsigned int x, const unsigned int y=0,
11750  const unsigned int z=0, const unsigned int c=0) const {
11751  return const_cast<CImg<T>*>(this)->operator()(x,y,z,c);
11752  }
11753 
11755 
11767  T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c,
11768  const ulongT wh, const ulongT whd=0) {
11769  cimg::unused(wh,whd);
11770  return (*this)(x,y,z,c);
11771  }
11772 
11774  const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c,
11775  const ulongT wh, const ulongT whd=0) const {
11776  cimg::unused(wh,whd);
11777  return (*this)(x,y,z,c);
11778  }
11779 #else
11780  T& operator()(const unsigned int x) {
11781  return _data[x];
11782  }
11783 
11784  const T& operator()(const unsigned int x) const {
11785  return _data[x];
11786  }
11787 
11788  T& operator()(const unsigned int x, const unsigned int y) {
11789  return _data[x + y*_width];
11790  }
11791 
11792  const T& operator()(const unsigned int x, const unsigned int y) const {
11793  return _data[x + y*_width];
11794  }
11795 
11796  T& operator()(const unsigned int x, const unsigned int y, const unsigned int z) {
11797  return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height];
11798  }
11799 
11800  const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z) const {
11801  return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height];
11802  }
11803 
11804  T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c) {
11805  return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height + c*(ulongT)_width*_height*_depth];
11806  }
11807 
11808  const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c) const {
11809  return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height + c*(ulongT)_width*_height*_depth];
11810  }
11811 
11812  T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int,
11813  const ulongT wh) {
11814  return _data[x + y*_width + z*wh];
11815  }
11816 
11817  const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int,
11818  const ulongT wh) const {
11819  return _data[x + y*_width + z*wh];
11820  }
11821 
11822  T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c,
11823  const ulongT wh, const ulongT whd) {
11824  return _data[x + y*_width + z*wh + c*whd];
11825  }
11826 
11827  const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c,
11828  const ulongT wh, const ulongT whd) const {
11829  return _data[x + y*_width + z*wh + c*whd];
11830  }
11831 #endif
11832 
11834 
11855  operator T*() {
11856  return _data;
11857  }
11858 
11860  operator const T*() const {
11861  return _data;
11862  }
11863 
11865 
11878  CImg<T>& operator=(const T& value) {
11879  return fill(value);
11880  }
11881 
11883 
11902  CImg<T>& operator=(const char *const expression) {
11903  const unsigned int omode = cimg::exception_mode();
11905  try {
11906  _fill(expression,true,true,0,0,"operator=",0);
11907  } catch (CImgException&) {
11908  cimg::exception_mode(omode);
11909  load(expression);
11910  }
11911  cimg::exception_mode(omode);
11912  return *this;
11913  }
11914 
11916 
11919  template<typename t>
11920  CImg<T>& operator=(const CImg<t>& img) {
11921  return assign(img);
11922  }
11923 
11925  CImg<T>& operator=(const CImg<T>& img) {
11926  return assign(img);
11927  }
11928 
11930 
11934  disp.snapshot(*this);
11935  return *this;
11936  }
11937 
11939 
11965  template<typename t>
11966  CImg<T>& operator+=(const t value) {
11967  if (is_empty()) return *this;
11968  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=524288))
11969  cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd + value);
11970  return *this;
11971  }
11972 
11974 
11981  CImg<T>& operator+=(const char *const expression) {
11982  return *this+=(+*this)._fill(expression,true,true,0,0,"operator+=",this);
11983  }
11984 
11986 
12006  template<typename t>
12007  CImg<T>& operator+=(const CImg<t>& img) {
12008  const ulongT siz = size(), isiz = img.size();
12009  if (siz && isiz) {
12010  if (is_overlapped(img)) return *this+=+img;
12011  T *ptrd = _data, *const ptre = _data + siz;
12012  if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
12013  for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
12014  *ptrd = (T)(*ptrd + *(ptrs++));
12015  for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)(*ptrd + *(ptrs++));
12016  }
12017  return *this;
12018  }
12019 
12021 
12027  if (is_empty()) return *this;
12028  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=524288))
12029  cimg_rof(*this,ptrd,T) ++*ptrd;
12030  return *this;
12031  }
12032 
12034 
12041  const CImg<T> copy(*this,false);
12042  ++*this;
12043  return copy;
12044  }
12045 
12047 
12055  CImg<T> operator+() const {
12056  return CImg<T>(*this,false);
12057  }
12058 
12060 
12064  template<typename t>
12065  CImg<_cimg_Tt> operator+(const t value) const {
12066  return CImg<_cimg_Tt>(*this,false)+=value;
12067  }
12068 
12070 
12074  CImg<Tfloat> operator+(const char *const expression) const {
12075  return CImg<Tfloat>(*this,false)+=expression;
12076  }
12077 
12079 
12083  template<typename t>
12084  CImg<_cimg_Tt> operator+(const CImg<t>& img) const {
12085  return CImg<_cimg_Tt>(*this,false)+=img;
12086  }
12087 
12089 
12092  template<typename t>
12093  CImg<T>& operator-=(const t value) {
12094  if (is_empty()) return *this;
12095  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=524288))
12096  cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd - value);
12097  return *this;
12098  }
12099 
12101 
12104  CImg<T>& operator-=(const char *const expression) {
12105  return *this-=(+*this)._fill(expression,true,true,0,0,"operator-=",this);
12106  }
12107 
12109 
12112  template<typename t>
12113  CImg<T>& operator-=(const CImg<t>& img) {
12114  const ulongT siz = size(), isiz = img.size();
12115  if (siz && isiz) {
12116  if (is_overlapped(img)) return *this-=+img;
12117  T *ptrd = _data, *const ptre = _data + siz;
12118  if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
12119  for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
12120  *ptrd = (T)(*ptrd - *(ptrs++));
12121  for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)(*ptrd - *(ptrs++));
12122  }
12123  return *this;
12124  }
12125 
12127 
12131  if (is_empty()) return *this;
12132  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=524288))
12133  cimg_rof(*this,ptrd,T) *ptrd = *ptrd - (T)1;
12134  return *this;
12135  }
12136 
12138 
12142  const CImg<T> copy(*this,false);
12143  --*this;
12144  return copy;
12145  }
12146 
12148 
12161  CImg<T> operator-() const {
12162  return CImg<T>(_width,_height,_depth,_spectrum,(T)0)-=*this;
12163  }
12164 
12166 
12170  template<typename t>
12171  CImg<_cimg_Tt> operator-(const t value) const {
12172  return CImg<_cimg_Tt>(*this,false)-=value;
12173  }
12174 
12176 
12180  CImg<Tfloat> operator-(const char *const expression) const {
12181  return CImg<Tfloat>(*this,false)-=expression;
12182  }
12183 
12185 
12189  template<typename t>
12190  CImg<_cimg_Tt> operator-(const CImg<t>& img) const {
12191  return CImg<_cimg_Tt>(*this,false)-=img;
12192  }
12193 
12195 
12198  template<typename t>
12199  CImg<T>& operator*=(const t value) {
12200  if (is_empty()) return *this;
12201  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=262144))
12202  cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd * value);
12203  return *this;
12204  }
12205 
12207 
12210  CImg<T>& operator*=(const char *const expression) {
12211  return mul((+*this)._fill(expression,true,true,0,0,"operator*=",this));
12212  }
12213 
12215 
12231  template<typename t>
12232  CImg<T>& operator*=(const CImg<t>& img) {
12233  return ((*this)*img).move_to(*this);
12234  }
12235 
12237 
12241  template<typename t>
12242  CImg<_cimg_Tt> operator*(const t value) const {
12243  return CImg<_cimg_Tt>(*this,false)*=value;
12244  }
12245 
12247 
12251  CImg<Tfloat> operator*(const char *const expression) const {
12252  return CImg<Tfloat>(*this,false)*=expression;
12253  }
12254 
12256 
12260  template<typename t>
12261  CImg<_cimg_Tt> operator*(const CImg<t>& img) const {
12262  if (_width!=img._height || _depth!=1 || _spectrum!=1)
12263  throw CImgArgumentException(_cimg_instance
12264  "operator*(): Invalid multiplication of instance by specified "
12265  "matrix (%u,%u,%u,%u,%p)",
12266  cimg_instance,
12267  img._width,img._height,img._depth,img._spectrum,img._data);
12268  CImg<_cimg_Tt> res(img._width,_height);
12269 #ifdef cimg_use_openmp
12270  cimg_pragma_openmp(parallel for collapse(2) cimg_openmp_if(size()>1024 && img.size()>1024))
12271  cimg_forXY(res,i,j) {
12272  _cimg_Ttdouble value = 0; cimg_forX(*this,k) value+=(*this)(k,j)*img(i,k); res(i,j) = (_cimg_Tt)value;
12273  }
12274 #else
12275  _cimg_Tt *ptrd = res._data;
12276  cimg_forXY(res,i,j) {
12277  _cimg_Ttdouble value = 0; cimg_forX(*this,k) value+=(*this)(k,j)*img(i,k); *(ptrd++) = (_cimg_Tt)value;
12278  }
12279 #endif
12280  return res;
12281  }
12282 
12284 
12287  template<typename t>
12288  CImg<T>& operator/=(const t value) {
12289  if (is_empty()) return *this;
12290  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
12291  cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd / value);
12292  return *this;
12293  }
12294 
12296 
12299  CImg<T>& operator/=(const char *const expression) {
12300  return div((+*this)._fill(expression,true,true,0,0,"operator/=",this));
12301  }
12302 
12304 
12314  template<typename t>
12315  CImg<T>& operator/=(const CImg<t>& img) {
12316  return (*this*img.get_invert()).move_to(*this);
12317  }
12318 
12320 
12324  template<typename t>
12325  CImg<_cimg_Tt> operator/(const t value) const {
12326  return CImg<_cimg_Tt>(*this,false)/=value;
12327  }
12328 
12330 
12334  CImg<Tfloat> operator/(const char *const expression) const {
12335  return CImg<Tfloat>(*this,false)/=expression;
12336  }
12337 
12339 
12343  template<typename t>
12344  CImg<_cimg_Tt> operator/(const CImg<t>& img) const {
12345  return (*this)*img.get_invert();
12346  }
12347 
12349 
12352  template<typename t>
12353  CImg<T>& operator%=(const t value) {
12354  if (is_empty()) return *this;
12355  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=16384))
12356  cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::mod(*ptrd,(T)value);
12357  return *this;
12358  }
12359 
12361 
12364  CImg<T>& operator%=(const char *const expression) {
12365  return *this%=(+*this)._fill(expression,true,true,0,0,"operator%=",this);
12366  }
12367 
12369 
12372  template<typename t>
12373  CImg<T>& operator%=(const CImg<t>& img) {
12374  const ulongT siz = size(), isiz = img.size();
12375  if (siz && isiz) {
12376  if (is_overlapped(img)) return *this%=+img;
12377  T *ptrd = _data, *const ptre = _data + siz;
12378  if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
12379  for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
12380  *ptrd = cimg::mod(*ptrd,(T)*(ptrs++));
12381  for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = cimg::mod(*ptrd,(T)*(ptrs++));
12382  }
12383  return *this;
12384  }
12385 
12387 
12391  template<typename t>
12392  CImg<_cimg_Tt> operator%(const t value) const {
12393  return CImg<_cimg_Tt>(*this,false)%=value;
12394  }
12395 
12397 
12401  CImg<Tfloat> operator%(const char *const expression) const {
12402  return CImg<Tfloat>(*this,false)%=expression;
12403  }
12404 
12406 
12410  template<typename t>
12411  CImg<_cimg_Tt> operator%(const CImg<t>& img) const {
12412  return CImg<_cimg_Tt>(*this,false)%=img;
12413  }
12414 
12416 
12419  template<typename t>
12420  CImg<T>& operator&=(const t value) {
12421  if (is_empty()) return *this;
12422  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
12423  cimg_rof(*this,ptrd,T) *ptrd = (T)((ulongT)*ptrd & (ulongT)value);
12424  return *this;
12425  }
12426 
12428 
12431  CImg<T>& operator&=(const char *const expression) {
12432  return *this&=(+*this)._fill(expression,true,true,0,0,"operator&=",this);
12433  }
12434 
12436 
12439  template<typename t>
12440  CImg<T>& operator&=(const CImg<t>& img) {
12441  const ulongT siz = size(), isiz = img.size();
12442  if (siz && isiz) {
12443  if (is_overlapped(img)) return *this&=+img;
12444  T *ptrd = _data, *const ptre = _data + siz;
12445  if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
12446  for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
12447  *ptrd = (T)((ulongT)*ptrd & (ulongT)*(ptrs++));
12448  for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((ulongT)*ptrd & (ulongT)*(ptrs++));
12449  }
12450  return *this;
12451  }
12452 
12454 
12458  template<typename t>
12459  CImg<T> operator&(const t value) const {
12460  return (+*this)&=value;
12461  }
12462 
12464 
12468  CImg<T> operator&(const char *const expression) const {
12469  return (+*this)&=expression;
12470  }
12471 
12473 
12477  template<typename t>
12478  CImg<T> operator&(const CImg<t>& img) const {
12479  return (+*this)&=img;
12480  }
12481 
12483 
12486  template<typename t>
12487  CImg<T>& operator|=(const t value) {
12488  if (is_empty()) return *this;
12489  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
12490  cimg_rof(*this,ptrd,T) *ptrd = (T)((ulongT)*ptrd | (ulongT)value);
12491  return *this;
12492  }
12493 
12495 
12498  CImg<T>& operator|=(const char *const expression) {
12499  return *this|=(+*this)._fill(expression,true,true,0,0,"operator|=",this);
12500  }
12501 
12503 
12506  template<typename t>
12507  CImg<T>& operator|=(const CImg<t>& img) {
12508  const ulongT siz = size(), isiz = img.size();
12509  if (siz && isiz) {
12510  if (is_overlapped(img)) return *this|=+img;
12511  T *ptrd = _data, *const ptre = _data + siz;
12512  if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
12513  for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
12514  *ptrd = (T)((ulongT)*ptrd | (ulongT)*(ptrs++));
12515  for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((ulongT)*ptrd | (ulongT)*(ptrs++));
12516  }
12517  return *this;
12518  }
12519 
12521 
12525  template<typename t>
12526  CImg<T> operator|(const t value) const {
12527  return (+*this)|=value;
12528  }
12529 
12531 
12535  CImg<T> operator|(const char *const expression) const {
12536  return (+*this)|=expression;
12537  }
12538 
12540 
12544  template<typename t>
12545  CImg<T> operator|(const CImg<t>& img) const {
12546  return (+*this)|=img;
12547  }
12548 
12550 
12555  template<typename t>
12556  CImg<T>& operator^=(const t value) {
12557  if (is_empty()) return *this;
12558  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
12559  cimg_rof(*this,ptrd,T) *ptrd = (T)((ulongT)*ptrd ^ (ulongT)value);
12560  return *this;
12561  }
12562 
12564 
12569  CImg<T>& operator^=(const char *const expression) {
12570  return *this^=(+*this)._fill(expression,true,true,0,0,"operator^=",this);
12571  }
12572 
12574 
12579  template<typename t>
12580  CImg<T>& operator^=(const CImg<t>& img) {
12581  const ulongT siz = size(), isiz = img.size();
12582  if (siz && isiz) {
12583  if (is_overlapped(img)) return *this^=+img;
12584  T *ptrd = _data, *const ptre = _data + siz;
12585  if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
12586  for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
12587  *ptrd = (T)((ulongT)*ptrd ^ (ulongT)*(ptrs++));
12588  for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((ulongT)*ptrd ^ (ulongT)*(ptrs++));
12589  }
12590  return *this;
12591  }
12592 
12594 
12598  template<typename t>
12599  CImg<T> operator^(const t value) const {
12600  return (+*this)^=value;
12601  }
12602 
12604 
12608  CImg<T> operator^(const char *const expression) const {
12609  return (+*this)^=expression;
12610  }
12611 
12613 
12617  template<typename t>
12618  CImg<T> operator^(const CImg<t>& img) const {
12619  return (+*this)^=img;
12620  }
12621 
12623 
12626  template<typename t>
12627  CImg<T>& operator<<=(const t value) {
12628  if (is_empty()) return *this;
12629  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=65536))
12630  cimg_rof(*this,ptrd,T) *ptrd = (T)(((longT)*ptrd) << (int)value);
12631  return *this;
12632  }
12633 
12635 
12638  CImg<T>& operator<<=(const char *const expression) {
12639  return *this<<=(+*this)._fill(expression,true,true,0,0,"operator<<=",this);
12640  }
12641 
12643 
12646  template<typename t>
12647  CImg<T>& operator<<=(const CImg<t>& img) {
12648  const ulongT siz = size(), isiz = img.size();
12649  if (siz && isiz) {
12650  if (is_overlapped(img)) return *this^=+img;
12651  T *ptrd = _data, *const ptre = _data + siz;
12652  if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
12653  for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
12654  *ptrd = (T)((longT)*ptrd << (int)*(ptrs++));
12655  for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((longT)*ptrd << (int)*(ptrs++));
12656  }
12657  return *this;
12658  }
12659 
12661 
12665  template<typename t>
12666  CImg<T> operator<<(const t value) const {
12667  return (+*this)<<=value;
12668  }
12669 
12671 
12675  CImg<T> operator<<(const char *const expression) const {
12676  return (+*this)<<=expression;
12677  }
12678 
12680 
12685  template<typename t>
12686  CImg<T> operator<<(const CImg<t>& img) const {
12687  return (+*this)<<=img;
12688  }
12689 
12691 
12694  template<typename t>
12695  CImg<T>& operator>>=(const t value) {
12696  if (is_empty()) return *this;
12697  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=65536))
12698  cimg_rof(*this,ptrd,T) *ptrd = (T)(((longT)*ptrd) >> (int)value);
12699  return *this;
12700  }
12701 
12703 
12706  CImg<T>& operator>>=(const char *const expression) {
12707  return *this>>=(+*this)._fill(expression,true,true,0,0,"operator>>=",this);
12708  }
12709 
12711 
12714  template<typename t>
12715  CImg<T>& operator>>=(const CImg<t>& img) {
12716  const ulongT siz = size(), isiz = img.size();
12717  if (siz && isiz) {
12718  if (is_overlapped(img)) return *this^=+img;
12719  T *ptrd = _data, *const ptre = _data + siz;
12720  if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
12721  for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
12722  *ptrd = (T)((longT)*ptrd >> (int)*(ptrs++));
12723  for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((longT)*ptrd >> (int)*(ptrs++));
12724  }
12725  return *this;
12726  }
12727 
12729 
12733  template<typename t>
12734  CImg<T> operator>>(const t value) const {
12735  return (+*this)>>=value;
12736  }
12737 
12739 
12743  CImg<T> operator>>(const char *const expression) const {
12744  return (+*this)>>=expression;
12745  }
12746 
12748 
12753  template<typename t>
12754  CImg<T> operator>>(const CImg<t>& img) const {
12755  return (+*this)>>=img;
12756  }
12757 
12759 
12762  CImg<T> operator~() const {
12763  CImg<T> res(_width,_height,_depth,_spectrum);
12764  const T *ptrs = _data;
12765  cimg_for(res,ptrd,T) { const ulongT value = (ulongT)*(ptrs++); *ptrd = (T)~value; }
12766  return res;
12767  }
12768 
12770 
12774  template<typename t>
12775  bool operator==(const t value) const {
12776  if (is_empty()) return false;
12777  typedef _cimg_Tt Tt;
12778  bool is_equal = true;
12779  for (T *ptrd = _data + size(); is_equal && ptrd>_data; is_equal = ((Tt)*(--ptrd)==(Tt)value)) {}
12780  return is_equal;
12781  }
12782 
12784 
12788  bool operator==(const char *const expression) const {
12789  return *this==(+*this)._fill(expression,true,true,0,0,"operator==",this);
12790  }
12791 
12793 
12811  template<typename t>
12812  bool operator==(const CImg<t>& img) const {
12813  typedef _cimg_Tt Tt;
12814  const ulongT siz = size();
12815  bool is_equal = true;
12816  if (siz!=img.size()) return false;
12817  t *ptrs = img._data + siz;
12818  for (T *ptrd = _data + siz; is_equal && ptrd>_data; is_equal = ((Tt)*(--ptrd)==(Tt)*(--ptrs))) {}
12819  return is_equal;
12820  }
12821 
12823 
12827  template<typename t>
12828  bool operator!=(const t value) const {
12829  return !((*this)==value);
12830  }
12831 
12833 
12837  bool operator!=(const char *const expression) const {
12838  return !((*this)==expression);
12839  }
12840 
12842 
12849  template<typename t>
12850  bool operator!=(const CImg<t>& img) const {
12851  return !((*this)==img);
12852  }
12853 
12855 
12884  template<typename t>
12886  return CImgList<_cimg_Tt>(*this,img);
12887  }
12888 
12890 
12899  template<typename t>
12901  return CImgList<_cimg_Tt>(list,false).insert(*this,0);
12902  }
12903 
12905 
12919  CImgList<T> operator<(const char axis) const {
12920  return get_split(axis);
12921  }
12922 
12924  //-------------------------------------
12925  //
12927 
12928  //-------------------------------------
12929 
12931 
12938  static const char* pixel_type() {
12939  return cimg::type<T>::string();
12940  }
12941 
12943 
12954  int width() const {
12955  return (int)_width;
12956  }
12957 
12959 
12969  int height() const {
12970  return (int)_height;
12971  }
12972 
12974 
12986  int depth() const {
12987  return (int)_depth;
12988  }
12989 
12991 
13005  int spectrum() const {
13006  return (int)_spectrum;
13007  }
13008 
13010 
13025  ulongT size() const {
13026  return (ulongT)_width*_height*_depth*_spectrum;
13027  }
13028 
13030 
13040  T* data() {
13041  return _data;
13042  }
13043 
13045  const T* data() const {
13046  return _data;
13047  }
13048 
13050 
13062 #if cimg_verbosity>=3
13063  T *data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) {
13064  const ulongT off = (ulongT)offset(x,y,z,c);
13065  if (off>=size())
13066  cimg::warn(_cimg_instance
13067  "data(): Invalid pointer request, at coordinates (%u,%u,%u,%u) [offset=%u].",
13068  cimg_instance,
13069  x,y,z,c,off);
13070  return _data + off;
13071  }
13072 
13074  const T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const {
13075  return const_cast<CImg<T>*>(this)->data(x,y,z,c);
13076  }
13077 #else
13078  T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) {
13079  return _data + x + (ulongT)y*_width + (ulongT)z*_width*_height + (ulongT)c*_width*_height*_depth;
13080  }
13081 
13082  const T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const {
13083  return _data + x + (ulongT)y*_width + (ulongT)z*_width*_height + (ulongT)c*_width*_height*_depth;
13084  }
13085 #endif
13086 
13088 
13103  longT offset(const int x, const int y=0, const int z=0, const int c=0) const {
13104  return x + (longT)y*_width + (longT)z*_width*_height + (longT)c*_width*_height*_depth;
13105  }
13106 
13108 
13113  iterator begin() {
13114  return _data;
13115  }
13116 
13118  const_iterator begin() const {
13119  return _data;
13120  }
13121 
13123 
13139  iterator end() {
13140  return _data + size();
13141  }
13142 
13144  const_iterator end() const {
13145  return _data + size();
13146  }
13147 
13149 
13154  T& front() {
13155  return *_data;
13156  }
13157 
13159  const T& front() const {
13160  return *_data;
13161  }
13162 
13164 
13170  T& back() {
13171  return *(_data + size() - 1);
13172  }
13173 
13175  const T& back() const {
13176  return *(_data + size() - 1);
13177  }
13178 
13180 
13192  T& at(const int offset, const T& out_value) {
13193  return (offset<0 || offset>=(int)size())?(cimg::temporary(out_value)=out_value):(*this)[offset];
13194  }
13195 
13197  T at(const int offset, const T& out_value) const {
13198  return (offset<0 || offset>=(int)size())?out_value:(*this)[offset];
13199  }
13200 
13202 
13215  T& at(const int offset) {
13216  if (is_empty())
13217  throw CImgInstanceException(_cimg_instance
13218  "at(): Empty instance.",
13219  cimg_instance);
13220  return _at(offset);
13221  }
13222 
13223  T& _at(const int offset) {
13224  const unsigned int siz = (unsigned int)size();
13225  return (*this)[offset<0?0:(unsigned int)offset>=siz?siz - 1:offset];
13226  }
13227 
13229  const T& at(const int offset) const {
13230  if (is_empty())
13231  throw CImgInstanceException(_cimg_instance
13232  "at(): Empty instance.",
13233  cimg_instance);
13234  return _at(offset);
13235  }
13236 
13237  const T& _at(const int offset) const {
13238  const unsigned int siz = (unsigned int)size();
13239  return (*this)[offset<0?0:(unsigned int)offset>=siz?siz - 1:offset];
13240  }
13241 
13243 
13259  T& atX(const int x, const int y, const int z, const int c, const T& out_value) {
13260  return (x<0 || x>=width())?(cimg::temporary(out_value)=out_value):(*this)(x,y,z,c);
13261  }
13262 
13264  T atX(const int x, const int y, const int z, const int c, const T& out_value) const {
13265  return (x<0 || x>=width())?out_value:(*this)(x,y,z,c);
13266  }
13267 
13269 
13286  T& atX(const int x, const int y=0, const int z=0, const int c=0) {
13287  if (is_empty())
13288  throw CImgInstanceException(_cimg_instance
13289  "atX(): Empty instance.",
13290  cimg_instance);
13291  return _atX(x,y,z,c);
13292  }
13293 
13294  T& _atX(const int x, const int y=0, const int z=0, const int c=0) {
13295  return (*this)(x<0?0:(x>=width()?width() - 1:x),y,z,c);
13296  }
13297 
13299  const T& atX(const int x, const int y=0, const int z=0, const int c=0) const {
13300  if (is_empty())
13301  throw CImgInstanceException(_cimg_instance
13302  "atX(): Empty instance.",
13303  cimg_instance);
13304  return _atX(x,y,z,c);
13305  }
13306 
13307  const T& _atX(const int x, const int y=0, const int z=0, const int c=0) const {
13308  return (*this)(x<0?0:(x>=width()?width() - 1:x),y,z,c);
13309  }
13310 
13312 
13315  T& atXY(const int x, const int y, const int z, const int c, const T& out_value) {
13316  return (x<0 || y<0 || x>=width() || y>=height())?(cimg::temporary(out_value)=out_value):(*this)(x,y,z,c);
13317  }
13318 
13320  T atXY(const int x, const int y, const int z, const int c, const T& out_value) const {
13321  return (x<0 || y<0 || x>=width() || y>=height())?out_value:(*this)(x,y,z,c);
13322  }
13323 
13325 
13331  T& atXY(const int x, const int y, const int z=0, const int c=0) {
13332  if (is_empty())
13333  throw CImgInstanceException(_cimg_instance
13334  "atXY(): Empty instance.",
13335  cimg_instance);
13336  return _atXY(x,y,z,c);
13337  }
13338 
13339  T& _atXY(const int x, const int y, const int z=0, const int c=0) {
13340  return (*this)(cimg::cut(x,0,width() - 1),
13341  cimg::cut(y,0,height() - 1),z,c);
13342  }
13343 
13345  const T& atXY(const int x, const int y, const int z=0, const int c=0) const {
13346  if (is_empty())
13347  throw CImgInstanceException(_cimg_instance
13348  "atXY(): Empty instance.",
13349  cimg_instance);
13350  return _atXY(x,y,z,c);
13351  }
13352 
13353  const T& _atXY(const int x, const int y, const int z=0, const int c=0) const {
13354  return (*this)(cimg::cut(x,0,width() - 1),
13355  cimg::cut(y,0,height() - 1),z,c);
13356  }
13357 
13359 
13363  T& atXYZ(const int x, const int y, const int z, const int c, const T& out_value) {
13364  return (x<0 || y<0 || z<0 || x>=width() || y>=height() || z>=depth())?
13365  (cimg::temporary(out_value)=out_value):(*this)(x,y,z,c);
13366  }
13367 
13369  T atXYZ(const int x, const int y, const int z, const int c, const T& out_value) const {
13370  return (x<0 || y<0 || z<0 || x>=width() || y>=height() || z>=depth())?out_value:(*this)(x,y,z,c);
13371  }
13372 
13374 
13380  T& atXYZ(const int x, const int y, const int z, const int c=0) {
13381  if (is_empty())
13382  throw CImgInstanceException(_cimg_instance
13383  "atXYZ(): Empty instance.",
13384  cimg_instance);
13385  return _atXYZ(x,y,z,c);
13386  }
13387 
13388  T& _atXYZ(const int x, const int y, const int z, const int c=0) {
13389  return (*this)(cimg::cut(x,0,width() - 1),
13390  cimg::cut(y,0,height() - 1),
13391  cimg::cut(z,0,depth() - 1),c);
13392  }
13393 
13395  const T& atXYZ(const int x, const int y, const int z, const int c=0) const {
13396  if (is_empty())
13397  throw CImgInstanceException(_cimg_instance
13398  "atXYZ(): Empty instance.",
13399  cimg_instance);
13400  return _atXYZ(x,y,z,c);
13401  }
13402 
13403  const T& _atXYZ(const int x, const int y, const int z, const int c=0) const {
13404  return (*this)(cimg::cut(x,0,width() - 1),
13405  cimg::cut(y,0,height() - 1),
13406  cimg::cut(z,0,depth() - 1),c);
13407  }
13408 
13410 
13414  T& atXYZC(const int x, const int y, const int z, const int c, const T& out_value) {
13415  return (x<0 || y<0 || z<0 || c<0 || x>=width() || y>=height() || z>=depth() || c>=spectrum())?
13416  (cimg::temporary(out_value)=out_value):(*this)(x,y,z,c);
13417  }
13418 
13420  T atXYZC(const int x, const int y, const int z, const int c, const T& out_value) const {
13421  return (x<0 || y<0 || z<0 || c<0 || x>=width() || y>=height() || z>=depth() || c>=spectrum())?out_value:
13422  (*this)(x,y,z,c);
13423  }
13424 
13426 
13432  T& atXYZC(const int x, const int y, const int z, const int c) {
13433  if (is_empty())
13434  throw CImgInstanceException(_cimg_instance
13435  "atXYZC(): Empty instance.",
13436  cimg_instance);
13437  return _atXYZC(x,y,z,c);
13438  }
13439 
13440  T& _atXYZC(const int x, const int y, const int z, const int c) {
13441  return (*this)(cimg::cut(x,0,width() - 1),
13442  cimg::cut(y,0,height() - 1),
13443  cimg::cut(z,0,depth() - 1),
13444  cimg::cut(c,0,spectrum() - 1));
13445  }
13446 
13448  const T& atXYZC(const int x, const int y, const int z, const int c) const {
13449  if (is_empty())
13450  throw CImgInstanceException(_cimg_instance
13451  "atXYZC(): Empty instance.",
13452  cimg_instance);
13453  return _atXYZC(x,y,z,c);
13454  }
13455 
13456  const T& _atXYZC(const int x, const int y, const int z, const int c) const {
13457  return (*this)(cimg::cut(x,0,width() - 1),
13458  cimg::cut(y,0,height() - 1),
13459  cimg::cut(z,0,depth() - 1),
13460  cimg::cut(c,0,spectrum() - 1));
13461  }
13462 
13464 
13479  Tfloat linear_atX(const float fx, const int y, const int z, const int c, const T& out_value) const {
13480  const int
13481  x = (int)fx - (fx>=0?0:1), nx = x + 1;
13482  const float
13483  dx = fx - x;
13484  const Tfloat
13485  Ic = (Tfloat)atX(x,y,z,c,out_value), In = (Tfloat)atXY(nx,y,z,c,out_value);
13486  return Ic + dx*(In - Ic);
13487  }
13488 
13490 
13506  Tfloat linear_atX(const float fx, const int y=0, const int z=0, const int c=0) const {
13507  if (is_empty())
13508  throw CImgInstanceException(_cimg_instance
13509  "linear_atX(): Empty instance.",
13510  cimg_instance);
13511 
13512  return _linear_atX(fx,y,z,c);
13513  }
13514 
13515  Tfloat _linear_atX(const float fx, const int y=0, const int z=0, const int c=0) const {
13516  const float
13517  nfx = cimg::cut(fx,0,width() - 1);
13518  const unsigned int
13519  x = (unsigned int)nfx;
13520  const float
13521  dx = nfx - x;
13522  const unsigned int
13523  nx = dx>0?x + 1:x;
13524  const Tfloat
13525  Ic = (Tfloat)(*this)(x,y,z,c), In = (Tfloat)(*this)(nx,y,z,c);
13526  return Ic + dx*(In - Ic);
13527  }
13528 
13530 
13534  Tfloat linear_atXY(const float fx, const float fy, const int z, const int c, const T& out_value) const {
13535  const int
13536  x = (int)fx - (fx>=0?0:1), nx = x + 1,
13537  y = (int)fy - (fy>=0?0:1), ny = y + 1;
13538  const float
13539  dx = fx - x,
13540  dy = fy - y;
13541  const Tfloat
13542  Icc = (Tfloat)atXY(x,y,z,c,out_value), Inc = (Tfloat)atXY(nx,y,z,c,out_value),
13543  Icn = (Tfloat)atXY(x,ny,z,c,out_value), Inn = (Tfloat)atXY(nx,ny,z,c,out_value);
13544  return Icc + dx*(Inc - Icc + dy*(Icc + Inn - Icn - Inc)) + dy*(Icn - Icc);
13545  }
13546 
13548 
13555  Tfloat linear_atXY(const float fx, const float fy, const int z=0, const int c=0) const {
13556  if (is_empty())
13557  throw CImgInstanceException(_cimg_instance
13558  "linear_atXY(): Empty instance.",
13559  cimg_instance);
13560 
13561  return _linear_atXY(fx,fy,z,c);
13562  }
13563 
13564  Tfloat _linear_atXY(const float fx, const float fy, const int z=0, const int c=0) const {
13565  const float
13566  nfx = cimg::cut(fx,0,width() - 1),
13567  nfy = cimg::cut(fy,0,height() - 1);
13568  const unsigned int
13569  x = (unsigned int)nfx,
13570  y = (unsigned int)nfy;
13571  const float
13572  dx = nfx - x,
13573  dy = nfy - y;
13574  const unsigned int
13575  nx = dx>0?x + 1:x,
13576  ny = dy>0?y + 1:y;
13577  const Tfloat
13578  Icc = (Tfloat)(*this)(x,y,z,c), Inc = (Tfloat)(*this)(nx,y,z,c),
13579  Icn = (Tfloat)(*this)(x,ny,z,c), Inn = (Tfloat)(*this)(nx,ny,z,c);
13580  return Icc + dx*(Inc - Icc + dy*(Icc + Inn - Icn - Inc)) + dy*(Icn - Icc);
13581  }
13582 
13584 
13588  Tfloat linear_atXYZ(const float fx, const float fy, const float fz, const int c, const T& out_value) const {
13589  const int
13590  x = (int)fx - (fx>=0?0:1), nx = x + 1,
13591  y = (int)fy - (fy>=0?0:1), ny = y + 1,
13592  z = (int)fz - (fz>=0?0:1), nz = z + 1;
13593  const float
13594  dx = fx - x,
13595  dy = fy - y,
13596  dz = fz - z;
13597  const Tfloat
13598  Iccc = (Tfloat)atXYZ(x,y,z,c,out_value), Incc = (Tfloat)atXYZ(nx,y,z,c,out_value),
13599  Icnc = (Tfloat)atXYZ(x,ny,z,c,out_value), Innc = (Tfloat)atXYZ(nx,ny,z,c,out_value),
13600  Iccn = (Tfloat)atXYZ(x,y,nz,c,out_value), Incn = (Tfloat)atXYZ(nx,y,nz,c,out_value),
13601  Icnn = (Tfloat)atXYZ(x,ny,nz,c,out_value), Innn = (Tfloat)atXYZ(nx,ny,nz,c,out_value);
13602  return Iccc +
13603  dx*(Incc - Iccc +
13604  dy*(Iccc + Innc - Icnc - Incc +
13605  dz*(Iccn + Innn + Icnc + Incc - Icnn - Incn - Iccc - Innc)) +
13606  dz*(Iccc + Incn - Iccn - Incc)) +
13607  dy*(Icnc - Iccc +
13608  dz*(Iccc + Icnn - Iccn - Icnc)) +
13609  dz*(Iccn - Iccc);
13610  }
13611 
13613 
13620  Tfloat linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int c=0) const {
13621  if (is_empty())
13622  throw CImgInstanceException(_cimg_instance
13623  "linear_atXYZ(): Empty instance.",
13624  cimg_instance);
13625 
13626  return _linear_atXYZ(fx,fy,fz,c);
13627  }
13628 
13629  Tfloat _linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int c=0) const {
13630  const float
13631  nfx = cimg::cut(fx,0,width() - 1),
13632  nfy = cimg::cut(fy,0,height() - 1),
13633  nfz = cimg::cut(fz,0,depth() - 1);
13634  const unsigned int
13635  x = (unsigned int)nfx,
13636  y = (unsigned int)nfy,
13637  z = (unsigned int)nfz;
13638  const float
13639  dx = nfx - x,
13640  dy = nfy - y,
13641  dz = nfz - z;
13642  const unsigned int
13643  nx = dx>0?x + 1:x,
13644  ny = dy>0?y + 1:y,
13645  nz = dz>0?z + 1:z;
13646  const Tfloat
13647  Iccc = (Tfloat)(*this)(x,y,z,c), Incc = (Tfloat)(*this)(nx,y,z,c),
13648  Icnc = (Tfloat)(*this)(x,ny,z,c), Innc = (Tfloat)(*this)(nx,ny,z,c),
13649  Iccn = (Tfloat)(*this)(x,y,nz,c), Incn = (Tfloat)(*this)(nx,y,nz,c),
13650  Icnn = (Tfloat)(*this)(x,ny,nz,c), Innn = (Tfloat)(*this)(nx,ny,nz,c);
13651  return Iccc +
13652  dx*(Incc - Iccc +
13653  dy*(Iccc + Innc - Icnc - Incc +
13654  dz*(Iccn + Innn + Icnc + Incc - Icnn - Incn - Iccc - Innc)) +
13655  dz*(Iccc + Incn - Iccn - Incc)) +
13656  dy*(Icnc - Iccc +
13657  dz*(Iccc + Icnn - Iccn - Icnc)) +
13658  dz*(Iccn - Iccc);
13659  }
13660 
13662 
13666  Tfloat linear_atXYZC(const float fx, const float fy, const float fz, const float fc, const T& out_value) const {
13667  const int
13668  x = (int)fx - (fx>=0?0:1), nx = x + 1,
13669  y = (int)fy - (fy>=0?0:1), ny = y + 1,
13670  z = (int)fz - (fz>=0?0:1), nz = z + 1,
13671  c = (int)fc - (fc>=0?0:1), nc = c + 1;
13672  const float
13673  dx = fx - x,
13674  dy = fy - y,
13675  dz = fz - z,
13676  dc = fc - c;
13677  const Tfloat
13678  Icccc = (Tfloat)atXYZC(x,y,z,c,out_value), Inccc = (Tfloat)atXYZC(nx,y,z,c,out_value),
13679  Icncc = (Tfloat)atXYZC(x,ny,z,c,out_value), Inncc = (Tfloat)atXYZC(nx,ny,z,c,out_value),
13680  Iccnc = (Tfloat)atXYZC(x,y,nz,c,out_value), Incnc = (Tfloat)atXYZC(nx,y,nz,c,out_value),
13681  Icnnc = (Tfloat)atXYZC(x,ny,nz,c,out_value), Innnc = (Tfloat)atXYZC(nx,ny,nz,c,out_value),
13682  Icccn = (Tfloat)atXYZC(x,y,z,nc,out_value), Inccn = (Tfloat)atXYZC(nx,y,z,nc,out_value),
13683  Icncn = (Tfloat)atXYZC(x,ny,z,nc,out_value), Inncn = (Tfloat)atXYZC(nx,ny,z,nc,out_value),
13684  Iccnn = (Tfloat)atXYZC(x,y,nz,nc,out_value), Incnn = (Tfloat)atXYZC(nx,y,nz,nc,out_value),
13685  Icnnn = (Tfloat)atXYZC(x,ny,nz,nc,out_value), Innnn = (Tfloat)atXYZC(nx,ny,nz,nc,out_value);
13686  return Icccc +
13687  dx*(Inccc - Icccc +
13688  dy*(Icccc + Inncc - Icncc - Inccc +
13689  dz*(Iccnc + Innnc + Icncc + Inccc - Icnnc - Incnc - Icccc - Inncc +
13690  dc*(Iccnn + Innnn + Icncn + Inccn + Icnnc + Incnc + Icccc + Inncc -
13691  Icnnn - Incnn - Icccn - Inncn - Iccnc - Innnc - Icncc - Inccc)) +
13692  dc*(Icccn + Inncn + Icncc + Inccc - Icncn - Inccn - Icccc - Inncc)) +
13693  dz*(Icccc + Incnc - Iccnc - Inccc +
13694  dc*(Icccn + Incnn + Iccnc + Inccc - Iccnn - Inccn - Icccc - Incnc)) +
13695  dc*(Icccc + Inccn - Inccc - Icccn)) +
13696  dy*(Icncc - Icccc +
13697  dz*(Icccc + Icnnc - Iccnc - Icncc +
13698  dc*(Icccn + Icnnn + Iccnc + Icncc - Iccnn - Icncn - Icccc - Icnnc)) +
13699  dc*(Icccc + Icncn - Icncc - Icccn)) +
13700  dz*(Iccnc - Icccc +
13701  dc*(Icccc + Iccnn - Iccnc - Icccn)) +
13702  dc*(Icccn -Icccc);
13703  }
13704 
13706 
13713  Tfloat linear_atXYZC(const float fx, const float fy=0, const float fz=0, const float fc=0) const {
13714  if (is_empty())
13715  throw CImgInstanceException(_cimg_instance
13716  "linear_atXYZC(): Empty instance.",
13717  cimg_instance);
13718 
13719  return _linear_atXYZC(fx,fy,fz,fc);
13720  }
13721 
13722  Tfloat _linear_atXYZC(const float fx, const float fy=0, const float fz=0, const float fc=0) const {
13723  const float
13724  nfx = cimg::cut(fx,0,width() - 1),
13725  nfy = cimg::cut(fy,0,height() - 1),
13726  nfz = cimg::cut(fz,0,depth() - 1),
13727  nfc = cimg::cut(fc,0,spectrum() - 1);
13728  const unsigned int
13729  x = (unsigned int)nfx,
13730  y = (unsigned int)nfy,
13731  z = (unsigned int)nfz,
13732  c = (unsigned int)nfc;
13733  const float
13734  dx = nfx - x,
13735  dy = nfy - y,
13736  dz = nfz - z,
13737  dc = nfc - c;
13738  const unsigned int
13739  nx = dx>0?x + 1:x,
13740  ny = dy>0?y + 1:y,
13741  nz = dz>0?z + 1:z,
13742  nc = dc>0?c + 1:c;
13743  const Tfloat
13744  Icccc = (Tfloat)(*this)(x,y,z,c), Inccc = (Tfloat)(*this)(nx,y,z,c),
13745  Icncc = (Tfloat)(*this)(x,ny,z,c), Inncc = (Tfloat)(*this)(nx,ny,z,c),
13746  Iccnc = (Tfloat)(*this)(x,y,nz,c), Incnc = (Tfloat)(*this)(nx,y,nz,c),
13747  Icnnc = (Tfloat)(*this)(x,ny,nz,c), Innnc = (Tfloat)(*this)(nx,ny,nz,c),
13748  Icccn = (Tfloat)(*this)(x,y,z,nc), Inccn = (Tfloat)(*this)(nx,y,z,nc),
13749  Icncn = (Tfloat)(*this)(x,ny,z,nc), Inncn = (Tfloat)(*this)(nx,ny,z,nc),
13750  Iccnn = (Tfloat)(*this)(x,y,nz,nc), Incnn = (Tfloat)(*this)(nx,y,nz,nc),
13751  Icnnn = (Tfloat)(*this)(x,ny,nz,nc), Innnn = (Tfloat)(*this)(nx,ny,nz,nc);
13752  return Icccc +
13753  dx*(Inccc - Icccc +
13754  dy*(Icccc + Inncc - Icncc - Inccc +
13755  dz*(Iccnc + Innnc + Icncc + Inccc - Icnnc - Incnc - Icccc - Inncc +
13756  dc*(Iccnn + Innnn + Icncn + Inccn + Icnnc + Incnc + Icccc + Inncc -
13757  Icnnn - Incnn - Icccn - Inncn - Iccnc - Innnc - Icncc - Inccc)) +
13758  dc*(Icccn + Inncn + Icncc + Inccc - Icncn - Inccn - Icccc - Inncc)) +
13759  dz*(Icccc + Incnc - Iccnc - Inccc +
13760  dc*(Icccn + Incnn + Iccnc + Inccc - Iccnn - Inccn - Icccc - Incnc)) +
13761  dc*(Icccc + Inccn - Inccc - Icccn)) +
13762  dy*(Icncc - Icccc +
13763  dz*(Icccc + Icnnc - Iccnc - Icncc +
13764  dc*(Icccn + Icnnn + Iccnc + Icncc - Iccnn - Icncn - Icccc - Icnnc)) +
13765  dc*(Icccc + Icncn - Icncc - Icccn)) +
13766  dz*(Iccnc - Icccc +
13767  dc*(Icccc + Iccnn - Iccnc - Icccn)) +
13768  dc*(Icccn - Icccc);
13769  }
13770 
13772 
13788  Tfloat cubic_atX(const float fx, const int y, const int z, const int c, const T& out_value) const {
13789  const int
13790  x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2;
13791  const float
13792  dx = fx - x;
13793  const Tfloat
13794  Ip = (Tfloat)atX(px,y,z,c,out_value), Ic = (Tfloat)atX(x,y,z,c,out_value),
13795  In = (Tfloat)atX(nx,y,z,c,out_value), Ia = (Tfloat)atX(ax,y,z,c,out_value);
13796  return Ic + 0.5f*(dx*(-Ip + In) + dx*dx*(2*Ip - 5*Ic + 4*In - Ia) + dx*dx*dx*(-Ip + 3*Ic - 3*In + Ia));
13797  }
13798 
13800 
13804  T cubic_cut_atX(const float fx, const int y, const int z, const int c, const T& out_value) const {
13805  return cimg::type<T>::cut(cubic_atX(fx,y,z,c,out_value));
13806  }
13807 
13809 
13825  Tfloat cubic_atX(const float fx, const int y=0, const int z=0, const int c=0) const {
13826  if (is_empty())
13827  throw CImgInstanceException(_cimg_instance
13828  "cubic_atX(): Empty instance.",
13829  cimg_instance);
13830  return _cubic_atX(fx,y,z,c);
13831  }
13832 
13833  Tfloat _cubic_atX(const float fx, const int y=0, const int z=0, const int c=0) const {
13834  const float
13835  nfx = cimg::cut(fx,0,width() - 1);
13836  const int
13837  x = (int)nfx;
13838  const float
13839  dx = nfx - x;
13840  const int
13841  px = x - 1<0?0:x - 1, nx = dx>0?x + 1:x, ax = x + 2>=width()?width() - 1:x + 2;
13842  const Tfloat
13843  Ip = (Tfloat)(*this)(px,y,z,c), Ic = (Tfloat)(*this)(x,y,z,c),
13844  In = (Tfloat)(*this)(nx,y,z,c), Ia = (Tfloat)(*this)(ax,y,z,c);
13845  return Ic + 0.5f*(dx*(-Ip + In) + dx*dx*(2*Ip - 5*Ic + 4*In - Ia) + dx*dx*dx*(-Ip + 3*Ic - 3*In + Ia));
13846  }
13847 
13849 
13853  T cubic_cut_atX(const float fx, const int y, const int z, const int c) const {
13854  return cimg::type<T>::cut(cubic_atX(fx,y,z,c));
13855  }
13856 
13857  T _cubic_cut_atX(const float fx, const int y, const int z, const int c) const {
13858  return cimg::type<T>::cut(_cubic_atX(fx,y,z,c));
13859  }
13860 
13862 
13866  Tfloat cubic_atXY(const float fx, const float fy, const int z, const int c, const T& out_value) const {
13867  const int
13868  x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2,
13869  y = (int)fy - (fy>=0?0:1), py = y - 1, ny = y + 1, ay = y + 2;
13870  const float dx = fx - x, dy = fy - y;
13871  const Tfloat
13872  Ipp = (Tfloat)atXY(px,py,z,c,out_value), Icp = (Tfloat)atXY(x,py,z,c,out_value),
13873  Inp = (Tfloat)atXY(nx,py,z,c,out_value), Iap = (Tfloat)atXY(ax,py,z,c,out_value),
13874  Ip = Icp + 0.5f*(dx*(-Ipp + Inp) + dx*dx*(2*Ipp - 5*Icp + 4*Inp - Iap) + dx*dx*dx*(-Ipp + 3*Icp - 3*Inp + Iap)),
13875  Ipc = (Tfloat)atXY(px,y,z,c,out_value), Icc = (Tfloat)atXY(x, y,z,c,out_value),
13876  Inc = (Tfloat)atXY(nx,y,z,c,out_value), Iac = (Tfloat)atXY(ax,y,z,c,out_value),
13877  Ic = Icc + 0.5f*(dx*(-Ipc + Inc) + dx*dx*(2*Ipc - 5*Icc + 4*Inc - Iac) + dx*dx*dx*(-Ipc + 3*Icc - 3*Inc + Iac)),
13878  Ipn = (Tfloat)atXY(px,ny,z,c,out_value), Icn = (Tfloat)atXY(x,ny,z,c,out_value),
13879  Inn = (Tfloat)atXY(nx,ny,z,c,out_value), Ian = (Tfloat)atXY(ax,ny,z,c,out_value),
13880  In = Icn + 0.5f*(dx*(-Ipn + Inn) + dx*dx*(2*Ipn - 5*Icn + 4*Inn - Ian) + dx*dx*dx*(-Ipn + 3*Icn - 3*Inn + Ian)),
13881  Ipa = (Tfloat)atXY(px,ay,z,c,out_value), Ica = (Tfloat)atXY(x,ay,z,c,out_value),
13882  Ina = (Tfloat)atXY(nx,ay,z,c,out_value), Iaa = (Tfloat)atXY(ax,ay,z,c,out_value),
13883  Ia = Ica + 0.5f*(dx*(-Ipa + Ina) + dx*dx*(2*Ipa - 5*Ica + 4*Ina - Iaa) + dx*dx*dx*(-Ipa + 3*Ica - 3*Ina + Iaa));
13884  return Ic + 0.5f*(dy*(-Ip + In) + dy*dy*(2*Ip - 5*Ic + 4*In - Ia) + dy*dy*dy*(-Ip + 3*Ic - 3*In + Ia));
13885  }
13886 
13888 
13892  T cubic_cut_atXY(const float fx, const float fy, const int z, const int c, const T& out_value) const {
13893  return cimg::type<T>::cut(cubic_atXY(fx,fy,z,c,out_value));
13894  }
13895 
13897 
13904  Tfloat cubic_atXY(const float fx, const float fy, const int z=0, const int c=0) const {
13905  if (is_empty())
13906  throw CImgInstanceException(_cimg_instance
13907  "cubic_atXY(): Empty instance.",
13908  cimg_instance);
13909  return _cubic_atXY(fx,fy,z,c);
13910  }
13911 
13912  Tfloat _cubic_atXY(const float fx, const float fy, const int z=0, const int c=0) const {
13913  const float
13914  nfx = cimg::cut(fx,0,width() - 1),
13915  nfy = cimg::cut(fy,0,height() - 1);
13916  const int x = (int)nfx, y = (int)nfy;
13917  const float dx = nfx - x, dy = nfy - y;
13918  const int
13919  px = x - 1<0?0:x - 1, nx = dx>0?x + 1:x, ax = x + 2>=width()?width() - 1:x + 2,
13920  py = y - 1<0?0:y - 1, ny = dy>0?y + 1:y, ay = y + 2>=height()?height() - 1:y + 2;
13921  const Tfloat
13922  Ipp = (Tfloat)(*this)(px,py,z,c), Icp = (Tfloat)(*this)(x,py,z,c), Inp = (Tfloat)(*this)(nx,py,z,c),
13923  Iap = (Tfloat)(*this)(ax,py,z,c),
13924  Ip = Icp + 0.5f*(dx*(-Ipp + Inp) + dx*dx*(2*Ipp - 5*Icp + 4*Inp - Iap) + dx*dx*dx*(-Ipp + 3*Icp - 3*Inp + Iap)),
13925  Ipc = (Tfloat)(*this)(px,y,z,c), Icc = (Tfloat)(*this)(x, y,z,c), Inc = (Tfloat)(*this)(nx,y,z,c),
13926  Iac = (Tfloat)(*this)(ax,y,z,c),
13927  Ic = Icc + 0.5f*(dx*(-Ipc + Inc) + dx*dx*(2*Ipc - 5*Icc + 4*Inc - Iac) + dx*dx*dx*(-Ipc + 3*Icc - 3*Inc + Iac)),
13928  Ipn = (Tfloat)(*this)(px,ny,z,c), Icn = (Tfloat)(*this)(x,ny,z,c), Inn = (Tfloat)(*this)(nx,ny,z,c),
13929  Ian = (Tfloat)(*this)(ax,ny,z,c),
13930  In = Icn + 0.5f*(dx*(-Ipn + Inn) + dx*dx*(2*Ipn - 5*Icn + 4*Inn - Ian) + dx*dx*dx*(-Ipn + 3*Icn - 3*Inn + Ian)),
13931  Ipa = (Tfloat)(*this)(px,ay,z,c), Ica = (Tfloat)(*this)(x,ay,z,c), Ina = (Tfloat)(*this)(nx,ay,z,c),
13932  Iaa = (Tfloat)(*this)(ax,ay,z,c),
13933  Ia = Ica + 0.5f*(dx*(-Ipa + Ina) + dx*dx*(2*Ipa - 5*Ica + 4*Ina - Iaa) + dx*dx*dx*(-Ipa + 3*Ica - 3*Ina + Iaa));
13934  return Ic + 0.5f*(dy*(-Ip + In) + dy*dy*(2*Ip - 5*Ic + 4*In - Ia) + dy*dy*dy*(-Ip + 3*Ic - 3*In + Ia));
13935  }
13936 
13938 
13942  T cubic_cut_atXY(const float fx, const float fy, const int z, const int c) const {
13943  return cimg::type<T>::cut(cubic_atXY(fx,fy,z,c));
13944  }
13945 
13946  T _cubic_cut_atXY(const float fx, const float fy, const int z, const int c) const {
13947  return cimg::type<T>::cut(_cubic_atXY(fx,fy,z,c));
13948  }
13949 
13951 
13955  Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c, const T& out_value) const {
13956  const int
13957  x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2,
13958  y = (int)fy - (fy>=0?0:1), py = y - 1, ny = y + 1, ay = y + 2,
13959  z = (int)fz - (fz>=0?0:1), pz = z - 1, nz = z + 1, az = z + 2;
13960  const float dx = fx - x, dy = fy - y, dz = fz - z;
13961  const Tfloat
13962  Ippp = (Tfloat)atXYZ(px,py,pz,c,out_value), Icpp = (Tfloat)atXYZ(x,py,pz,c,out_value),
13963  Inpp = (Tfloat)atXYZ(nx,py,pz,c,out_value), Iapp = (Tfloat)atXYZ(ax,py,pz,c,out_value),
13964  Ipp = Icpp + 0.5f*(dx*(-Ippp + Inpp) + dx*dx*(2*Ippp - 5*Icpp + 4*Inpp - Iapp) +
13965  dx*dx*dx*(-Ippp + 3*Icpp - 3*Inpp + Iapp)),
13966  Ipcp = (Tfloat)atXYZ(px,y,pz,c,out_value), Iccp = (Tfloat)atXYZ(x, y,pz,c,out_value),
13967  Incp = (Tfloat)atXYZ(nx,y,pz,c,out_value), Iacp = (Tfloat)atXYZ(ax,y,pz,c,out_value),
13968  Icp = Iccp + 0.5f*(dx*(-Ipcp + Incp) + dx*dx*(2*Ipcp - 5*Iccp + 4*Incp - Iacp) +
13969  dx*dx*dx*(-Ipcp + 3*Iccp - 3*Incp + Iacp)),
13970  Ipnp = (Tfloat)atXYZ(px,ny,pz,c,out_value), Icnp = (Tfloat)atXYZ(x,ny,pz,c,out_value),
13971  Innp = (Tfloat)atXYZ(nx,ny,pz,c,out_value), Ianp = (Tfloat)atXYZ(ax,ny,pz,c,out_value),
13972  Inp = Icnp + 0.5f*(dx*(-Ipnp + Innp) + dx*dx*(2*Ipnp - 5*Icnp + 4*Innp - Ianp) +
13973  dx*dx*dx*(-Ipnp + 3*Icnp - 3*Innp + Ianp)),
13974  Ipap = (Tfloat)atXYZ(px,ay,pz,c,out_value), Icap = (Tfloat)atXYZ(x,ay,pz,c,out_value),
13975  Inap = (Tfloat)atXYZ(nx,ay,pz,c,out_value), Iaap = (Tfloat)atXYZ(ax,ay,pz,c,out_value),
13976  Iap = Icap + 0.5f*(dx*(-Ipap + Inap) + dx*dx*(2*Ipap - 5*Icap + 4*Inap - Iaap) +
13977  dx*dx*dx*(-Ipap + 3*Icap - 3*Inap + Iaap)),
13978  Ip = Icp + 0.5f*(dy*(-Ipp + Inp) + dy*dy*(2*Ipp - 5*Icp + 4*Inp - Iap) +
13979  dy*dy*dy*(-Ipp + 3*Icp - 3*Inp + Iap)),
13980  Ippc = (Tfloat)atXYZ(px,py,z,c,out_value), Icpc = (Tfloat)atXYZ(x,py,z,c,out_value),
13981  Inpc = (Tfloat)atXYZ(nx,py,z,c,out_value), Iapc = (Tfloat)atXYZ(ax,py,z,c,out_value),
13982  Ipc = Icpc + 0.5f*(dx*(-Ippc + Inpc) + dx*dx*(2*Ippc - 5*Icpc + 4*Inpc - Iapc) +
13983  dx*dx*dx*(-Ippc + 3*Icpc - 3*Inpc + Iapc)),
13984  Ipcc = (Tfloat)atXYZ(px,y,z,c,out_value), Iccc = (Tfloat)atXYZ(x, y,z,c,out_value),
13985  Incc = (Tfloat)atXYZ(nx,y,z,c,out_value), Iacc = (Tfloat)atXYZ(ax,y,z,c,out_value),
13986  Icc = Iccc + 0.5f*(dx*(-Ipcc + Incc) + dx*dx*(2*Ipcc - 5*Iccc + 4*Incc - Iacc) +
13987  dx*dx*dx*(-Ipcc + 3*Iccc - 3*Incc + Iacc)),
13988  Ipnc = (Tfloat)atXYZ(px,ny,z,c,out_value), Icnc = (Tfloat)atXYZ(x,ny,z,c,out_value),
13989  Innc = (Tfloat)atXYZ(nx,ny,z,c,out_value), Ianc = (Tfloat)atXYZ(ax,ny,z,c,out_value),
13990  Inc = Icnc + 0.5f*(dx*(-Ipnc + Innc) + dx*dx*(2*Ipnc - 5*Icnc + 4*Innc - Ianc) +
13991  dx*dx*dx*(-Ipnc + 3*Icnc - 3*Innc + Ianc)),
13992  Ipac = (Tfloat)atXYZ(px,ay,z,c,out_value), Icac = (Tfloat)atXYZ(x,ay,z,c,out_value),
13993  Inac = (Tfloat)atXYZ(nx,ay,z,c,out_value), Iaac = (Tfloat)atXYZ(ax,ay,z,c,out_value),
13994  Iac = Icac + 0.5f*(dx*(-Ipac + Inac) + dx*dx*(2*Ipac - 5*Icac + 4*Inac - Iaac) +
13995  dx*dx*dx*(-Ipac + 3*Icac - 3*Inac + Iaac)),
13996  Ic = Icc + 0.5f*(dy*(-Ipc + Inc) + dy*dy*(2*Ipc - 5*Icc + 4*Inc - Iac) +
13997  dy*dy*dy*(-Ipc + 3*Icc - 3*Inc + Iac)),
13998  Ippn = (Tfloat)atXYZ(px,py,nz,c,out_value), Icpn = (Tfloat)atXYZ(x,py,nz,c,out_value),
13999  Inpn = (Tfloat)atXYZ(nx,py,nz,c,out_value), Iapn = (Tfloat)atXYZ(ax,py,nz,c,out_value),
14000  Ipn = Icpn + 0.5f*(dx*(-Ippn + Inpn) + dx*dx*(2*Ippn - 5*Icpn + 4*Inpn - Iapn) +
14001  dx*dx*dx*(-Ippn + 3*Icpn - 3*Inpn + Iapn)),
14002  Ipcn = (Tfloat)atXYZ(px,y,nz,c,out_value), Iccn = (Tfloat)atXYZ(x, y,nz,c,out_value),
14003  Incn = (Tfloat)atXYZ(nx,y,nz,c,out_value), Iacn = (Tfloat)atXYZ(ax,y,nz,c,out_value),
14004  Icn = Iccn + 0.5f*(dx*(-Ipcn + Incn) + dx*dx*(2*Ipcn - 5*Iccn + 4*Incn - Iacn) +
14005  dx*dx*dx*(-Ipcn + 3*Iccn - 3*Incn + Iacn)),
14006  Ipnn = (Tfloat)atXYZ(px,ny,nz,c,out_value), Icnn = (Tfloat)atXYZ(x,ny,nz,c,out_value),
14007  Innn = (Tfloat)atXYZ(nx,ny,nz,c,out_value), Iann = (Tfloat)atXYZ(ax,ny,nz,c,out_value),
14008  Inn = Icnn + 0.5f*(dx*(-Ipnn + Innn) + dx*dx*(2*Ipnn - 5*Icnn + 4*Innn - Iann) +
14009  dx*dx*dx*(-Ipnn + 3*Icnn - 3*Innn + Iann)),
14010  Ipan = (Tfloat)atXYZ(px,ay,nz,c,out_value), Ican = (Tfloat)atXYZ(x,ay,nz,c,out_value),
14011  Inan = (Tfloat)atXYZ(nx,ay,nz,c,out_value), Iaan = (Tfloat)atXYZ(ax,ay,nz,c,out_value),
14012  Ian = Ican + 0.5f*(dx*(-Ipan + Inan) + dx*dx*(2*Ipan - 5*Ican + 4*Inan - Iaan) +
14013  dx*dx*dx*(-Ipan + 3*Ican - 3*Inan + Iaan)),
14014  In = Icn + 0.5f*(dy*(-Ipn + Inn) + dy*dy*(2*Ipn - 5*Icn + 4*Inn - Ian) +
14015  dy*dy*dy*(-Ipn + 3*Icn - 3*Inn + Ian)),
14016  Ippa = (Tfloat)atXYZ(px,py,az,c,out_value), Icpa = (Tfloat)atXYZ(x,py,az,c,out_value),
14017  Inpa = (Tfloat)atXYZ(nx,py,az,c,out_value), Iapa = (Tfloat)atXYZ(ax,py,az,c,out_value),
14018  Ipa = Icpa + 0.5f*(dx*(-Ippa + Inpa) + dx*dx*(2*Ippa - 5*Icpa + 4*Inpa - Iapa) +
14019  dx*dx*dx*(-Ippa + 3*Icpa - 3*Inpa + Iapa)),
14020  Ipca = (Tfloat)atXYZ(px,y,az,c,out_value), Icca = (Tfloat)atXYZ(x, y,az,c,out_value),
14021  Inca = (Tfloat)atXYZ(nx,y,az,c,out_value), Iaca = (Tfloat)atXYZ(ax,y,az,c,out_value),
14022  Ica = Icca + 0.5f*(dx*(-Ipca + Inca) + dx*dx*(2*Ipca - 5*Icca + 4*Inca - Iaca) +
14023  dx*dx*dx*(-Ipca + 3*Icca - 3*Inca + Iaca)),
14024  Ipna = (Tfloat)atXYZ(px,ny,az,c,out_value), Icna = (Tfloat)atXYZ(x,ny,az,c,out_value),
14025  Inna = (Tfloat)atXYZ(nx,ny,az,c,out_value), Iana = (Tfloat)atXYZ(ax,ny,az,c,out_value),
14026  Ina = Icna + 0.5f*(dx*(-Ipna + Inna) + dx*dx*(2*Ipna - 5*Icna + 4*Inna - Iana) +
14027  dx*dx*dx*(-Ipna + 3*Icna - 3*Inna + Iana)),
14028  Ipaa = (Tfloat)atXYZ(px,ay,az,c,out_value), Icaa = (Tfloat)atXYZ(x,ay,az,c,out_value),
14029  Inaa = (Tfloat)atXYZ(nx,ay,az,c,out_value), Iaaa = (Tfloat)atXYZ(ax,ay,az,c,out_value),
14030  Iaa = Icaa + 0.5f*(dx*(-Ipaa + Inaa) + dx*dx*(2*Ipaa - 5*Icaa + 4*Inaa - Iaaa) +
14031  dx*dx*dx*(-Ipaa + 3*Icaa - 3*Inaa + Iaaa)),
14032  Ia = Ica + 0.5f*(dy*(-Ipa + Ina) + dy*dy*(2*Ipa - 5*Ica + 4*Ina - Iaa) +
14033  dy*dy*dy*(-Ipa + 3*Ica - 3*Ina + Iaa));
14034  return Ic + 0.5f*(dz*(-Ip + In) + dz*dz*(2*Ip - 5*Ic + 4*In - Ia) + dz*dz*dz*(-Ip + 3*Ic - 3*In + Ia));
14035  }
14036 
14038 
14042  T cubic_cut_atXYZ(const float fx, const float fy, const float fz, const int c, const T& out_value) const {
14043  return cimg::type<T>::cut(cubic_atXYZ(fx,fy,fz,c,out_value));
14044  }
14045 
14047 
14054  Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c=0) const {
14055  if (is_empty())
14056  throw CImgInstanceException(_cimg_instance
14057  "cubic_atXYZ(): Empty instance.",
14058  cimg_instance);
14059  return _cubic_atXYZ(fx,fy,fz,c);
14060  }
14061 
14062  Tfloat _cubic_atXYZ(const float fx, const float fy, const float fz, const int c=0) const {
14063  const float
14064  nfx = cimg::cut(fx,0,width() - 1),
14065  nfy = cimg::cut(fy,0,height() - 1),
14066  nfz = cimg::cut(fz,0,depth() - 1);
14067  const int x = (int)nfx, y = (int)nfy, z = (int)nfz;
14068  const float dx = nfx - x, dy = nfy - y, dz = nfz - z;
14069  const int
14070  px = x - 1<0?0:x - 1, nx = dx>0?x + 1:x, ax = x + 2>=width()?width() - 1:x + 2,
14071  py = y - 1<0?0:y - 1, ny = dy>0?y + 1:y, ay = y + 2>=height()?height() - 1:y + 2,
14072  pz = z - 1<0?0:z - 1, nz = dz>0?z + 1:z, az = z + 2>=depth()?depth() - 1:z + 2;
14073  const Tfloat
14074  Ippp = (Tfloat)(*this)(px,py,pz,c), Icpp = (Tfloat)(*this)(x,py,pz,c),
14075  Inpp = (Tfloat)(*this)(nx,py,pz,c), Iapp = (Tfloat)(*this)(ax,py,pz,c),
14076  Ipp = Icpp + 0.5f*(dx*(-Ippp + Inpp) + dx*dx*(2*Ippp - 5*Icpp + 4*Inpp - Iapp) +
14077  dx*dx*dx*(-Ippp + 3*Icpp - 3*Inpp + Iapp)),
14078  Ipcp = (Tfloat)(*this)(px,y,pz,c), Iccp = (Tfloat)(*this)(x, y,pz,c),
14079  Incp = (Tfloat)(*this)(nx,y,pz,c), Iacp = (Tfloat)(*this)(ax,y,pz,c),
14080  Icp = Iccp + 0.5f*(dx*(-Ipcp + Incp) + dx*dx*(2*Ipcp - 5*Iccp + 4*Incp - Iacp) +
14081  dx*dx*dx*(-Ipcp + 3*Iccp - 3*Incp + Iacp)),
14082  Ipnp = (Tfloat)(*this)(px,ny,pz,c), Icnp = (Tfloat)(*this)(x,ny,pz,c),
14083  Innp = (Tfloat)(*this)(nx,ny,pz,c), Ianp = (Tfloat)(*this)(ax,ny,pz,c),
14084  Inp = Icnp + 0.5f*(dx*(-Ipnp + Innp) + dx*dx*(2*Ipnp - 5*Icnp + 4*Innp - Ianp) +
14085  dx*dx*dx*(-Ipnp + 3*Icnp - 3*Innp + Ianp)),
14086  Ipap = (Tfloat)(*this)(px,ay,pz,c), Icap = (Tfloat)(*this)(x,ay,pz,c),
14087  Inap = (Tfloat)(*this)(nx,ay,pz,c), Iaap = (Tfloat)(*this)(ax,ay,pz,c),
14088  Iap = Icap + 0.5f*(dx*(-Ipap + Inap) + dx*dx*(2*Ipap - 5*Icap + 4*Inap - Iaap) +
14089  dx*dx*dx*(-Ipap + 3*Icap - 3*Inap + Iaap)),
14090  Ip = Icp + 0.5f*(dy*(-Ipp + Inp) + dy*dy*(2*Ipp - 5*Icp + 4*Inp - Iap) +
14091  dy*dy*dy*(-Ipp + 3*Icp - 3*Inp + Iap)),
14092  Ippc = (Tfloat)(*this)(px,py,z,c), Icpc = (Tfloat)(*this)(x,py,z,c),
14093  Inpc = (Tfloat)(*this)(nx,py,z,c), Iapc = (Tfloat)(*this)(ax,py,z,c),
14094  Ipc = Icpc + 0.5f*(dx*(-Ippc + Inpc) + dx*dx*(2*Ippc - 5*Icpc + 4*Inpc - Iapc) +
14095  dx*dx*dx*(-Ippc + 3*Icpc - 3*Inpc + Iapc)),
14096  Ipcc = (Tfloat)(*this)(px,y,z,c), Iccc = (Tfloat)(*this)(x, y,z,c),
14097  Incc = (Tfloat)(*this)(nx,y,z,c), Iacc = (Tfloat)(*this)(ax,y,z,c),
14098  Icc = Iccc + 0.5f*(dx*(-Ipcc + Incc) + dx*dx*(2*Ipcc - 5*Iccc + 4*Incc - Iacc) +
14099  dx*dx*dx*(-Ipcc + 3*Iccc - 3*Incc + Iacc)),
14100  Ipnc = (Tfloat)(*this)(px,ny,z,c), Icnc = (Tfloat)(*this)(x,ny,z,c),
14101  Innc = (Tfloat)(*this)(nx,ny,z,c), Ianc = (Tfloat)(*this)(ax,ny,z,c),
14102  Inc = Icnc + 0.5f*(dx*(-Ipnc + Innc) + dx*dx*(2*Ipnc - 5*Icnc + 4*Innc - Ianc) +
14103  dx*dx*dx*(-Ipnc + 3*Icnc - 3*Innc + Ianc)),
14104  Ipac = (Tfloat)(*this)(px,ay,z,c), Icac = (Tfloat)(*this)(x,ay,z,c),
14105  Inac = (Tfloat)(*this)(nx,ay,z,c), Iaac = (Tfloat)(*this)(ax,ay,z,c),
14106  Iac = Icac + 0.5f*(dx*(-Ipac + Inac) + dx*dx*(2*Ipac - 5*Icac + 4*Inac - Iaac) +
14107  dx*dx*dx*(-Ipac + 3*Icac - 3*Inac + Iaac)),
14108  Ic = Icc + 0.5f*(dy*(-Ipc + Inc) + dy*dy*(2*Ipc - 5*Icc + 4*Inc - Iac) +
14109  dy*dy*dy*(-Ipc + 3*Icc - 3*Inc + Iac)),
14110  Ippn = (Tfloat)(*this)(px,py,nz,c), Icpn = (Tfloat)(*this)(x,py,nz,c),
14111  Inpn = (Tfloat)(*this)(nx,py,nz,c), Iapn = (Tfloat)(*this)(ax,py,nz,c),
14112  Ipn = Icpn + 0.5f*(dx*(-Ippn + Inpn) + dx*dx*(2*Ippn - 5*Icpn + 4*Inpn - Iapn) +
14113  dx*dx*dx*(-Ippn + 3*Icpn - 3*Inpn + Iapn)),
14114  Ipcn = (Tfloat)(*this)(px,y,nz,c), Iccn = (Tfloat)(*this)(x, y,nz,c),
14115  Incn = (Tfloat)(*this)(nx,y,nz,c), Iacn = (Tfloat)(*this)(ax,y,nz,c),
14116  Icn = Iccn + 0.5f*(dx*(-Ipcn + Incn) + dx*dx*(2*Ipcn - 5*Iccn + 4*Incn - Iacn) +
14117  dx*dx*dx*(-Ipcn + 3*Iccn - 3*Incn + Iacn)),
14118  Ipnn = (Tfloat)(*this)(px,ny,nz,c), Icnn = (Tfloat)(*this)(x,ny,nz,c),
14119  Innn = (Tfloat)(*this)(nx,ny,nz,c), Iann = (Tfloat)(*this)(ax,ny,nz,c),
14120  Inn = Icnn + 0.5f*(dx*(-Ipnn + Innn) + dx*dx*(2*Ipnn - 5*Icnn + 4*Innn - Iann) +
14121  dx*dx*dx*(-Ipnn + 3*Icnn - 3*Innn + Iann)),
14122  Ipan = (Tfloat)(*this)(px,ay,nz,c), Ican = (Tfloat)(*this)(x,ay,nz,c),
14123  Inan = (Tfloat)(*this)(nx,ay,nz,c), Iaan = (Tfloat)(*this)(ax,ay,nz,c),
14124  Ian = Ican + 0.5f*(dx*(-Ipan + Inan) + dx*dx*(2*Ipan - 5*Ican + 4*Inan - Iaan) +
14125  dx*dx*dx*(-Ipan + 3*Ican - 3*Inan + Iaan)),
14126  In = Icn + 0.5f*(dy*(-Ipn + Inn) + dy*dy*(2*Ipn - 5*Icn + 4*Inn - Ian) +
14127  dy*dy*dy*(-Ipn + 3*Icn - 3*Inn + Ian)),
14128  Ippa = (Tfloat)(*this)(px,py,az,c), Icpa = (Tfloat)(*this)(x,py,az,c),
14129  Inpa = (Tfloat)(*this)(nx,py,az,c), Iapa = (Tfloat)(*this)(ax,py,az,c),
14130  Ipa = Icpa + 0.5f*(dx*(-Ippa + Inpa) + dx*dx*(2*Ippa - 5*Icpa + 4*Inpa - Iapa) +
14131  dx*dx*dx*(-Ippa + 3*Icpa - 3*Inpa + Iapa)),
14132  Ipca = (Tfloat)(*this)(px,y,az,c), Icca = (Tfloat)(*this)(x, y,az,c),
14133  Inca = (Tfloat)(*this)(nx,y,az,c), Iaca = (Tfloat)(*this)(ax,y,az,c),
14134  Ica = Icca + 0.5f*(dx*(-Ipca + Inca) + dx*dx*(2*Ipca - 5*Icca + 4*Inca - Iaca) +
14135  dx*dx*dx*(-Ipca + 3*Icca - 3*Inca + Iaca)),
14136  Ipna = (Tfloat)(*this)(px,ny,az,c), Icna = (Tfloat)(*this)(x,ny,az,c),
14137  Inna = (Tfloat)(*this)(nx,ny,az,c), Iana = (Tfloat)(*this)(ax,ny,az,c),
14138  Ina = Icna + 0.5f*(dx*(-Ipna + Inna) + dx*dx*(2*Ipna - 5*Icna + 4*Inna - Iana) +
14139  dx*dx*dx*(-Ipna + 3*Icna - 3*Inna + Iana)),
14140  Ipaa = (Tfloat)(*this)(px,ay,az,c), Icaa = (Tfloat)(*this)(x,ay,az,c),
14141  Inaa = (Tfloat)(*this)(nx,ay,az,c), Iaaa = (Tfloat)(*this)(ax,ay,az,c),
14142  Iaa = Icaa + 0.5f*(dx*(-Ipaa + Inaa) + dx*dx*(2*Ipaa - 5*Icaa + 4*Inaa - Iaaa) +
14143  dx*dx*dx*(-Ipaa + 3*Icaa - 3*Inaa + Iaaa)),
14144  Ia = Ica + 0.5f*(dy*(-Ipa + Ina) + dy*dy*(2*Ipa - 5*Ica + 4*Ina - Iaa) +
14145  dy*dy*dy*(-Ipa + 3*Ica - 3*Ina + Iaa));
14146  return Ic + 0.5f*(dz*(-Ip + In) + dz*dz*(2*Ip - 5*Ic + 4*In - Ia) + dz*dz*dz*(-Ip + 3*Ic - 3*In + Ia));
14147  }
14148 
14150 
14154  T cubic_cut_atXYZ(const float fx, const float fy, const float fz, const int c) const {
14155  return cimg::type<T>::cut(cubic_atXYZ(fx,fy,fz,c));
14156  }
14157 
14158  T _cubic_cut_atXYZ(const float fx, const float fy, const float fz, const int c) const {
14159  return cimg::type<T>::cut(_cubic_atXYZ(fx,fy,fz,c));
14160  }
14161 
14163 
14177  CImg<T>& set_linear_atX(const T& value, const float fx, const int y=0, const int z=0, const int c=0,
14178  const bool is_added=false) {
14179  const int
14180  x = (int)fx - (fx>=0?0:1), nx = x + 1;
14181  const float
14182  dx = fx - x;
14183  if (y>=0 && y<height() && z>=0 && z<depth() && c>=0 && c<spectrum()) {
14184  if (x>=0 && x<width()) {
14185  const float w1 = 1 - dx, w2 = is_added?1:(1 - w1);
14186  (*this)(x,y,z,c) = (T)(w1*value + w2*(*this)(x,y,z,c));
14187  }
14188  if (nx>=0 && nx<width()) {
14189  const float w1 = dx, w2 = is_added?1:(1 - w1);
14190  (*this)(nx,y,z,c) = (T)(w1*value + w2*(*this)(nx,y,z,c));
14191  }
14192  }
14193  return *this;
14194  }
14195 
14197 
14201  CImg<T>& set_linear_atXY(const T& value, const float fx, const float fy=0, const int z=0, const int c=0,
14202  const bool is_added=false) {
14203  const int
14204  x = (int)fx - (fx>=0?0:1), nx = x + 1,
14205  y = (int)fy - (fy>=0?0:1), ny = y + 1;
14206  const float
14207  dx = fx - x,
14208  dy = fy - y;
14209  if (z>=0 && z<depth() && c>=0 && c<spectrum()) {
14210  if (y>=0 && y<height()) {
14211  if (x>=0 && x<width()) {
14212  const float w1 = (1 - dx)*(1 - dy), w2 = is_added?1:(1 - w1);
14213  (*this)(x,y,z,c) = (T)(w1*value + w2*(*this)(x,y,z,c));
14214  }
14215  if (nx>=0 && nx<width()) {
14216  const float w1 = dx*(1 - dy), w2 = is_added?1:(1 - w1);
14217  (*this)(nx,y,z,c) = (T)(w1*value + w2*(*this)(nx,y,z,c));
14218  }
14219  }
14220  if (ny>=0 && ny<height()) {
14221  if (x>=0 && x<width()) {
14222  const float w1 = (1 - dx)*dy, w2 = is_added?1:(1 - w1);
14223  (*this)(x,ny,z,c) = (T)(w1*value + w2*(*this)(x,ny,z,c));
14224  }
14225  if (nx>=0 && nx<width()) {
14226  const float w1 = dx*dy, w2 = is_added?1:(1 - w1);
14227  (*this)(nx,ny,z,c) = (T)(w1*value + w2*(*this)(nx,ny,z,c));
14228  }
14229  }
14230  }
14231  return *this;
14232  }
14233 
14235 
14239  CImg<T>& set_linear_atXYZ(const T& value, const float fx, const float fy=0, const float fz=0, const int c=0,
14240  const bool is_added=false) {
14241  const int
14242  x = (int)fx - (fx>=0?0:1), nx = x + 1,
14243  y = (int)fy - (fy>=0?0:1), ny = y + 1,
14244  z = (int)fz - (fz>=0?0:1), nz = z + 1;
14245  const float
14246  dx = fx - x,
14247  dy = fy - y,
14248  dz = fz - z;
14249  if (c>=0 && c<spectrum()) {
14250  if (z>=0 && z<depth()) {
14251  if (y>=0 && y<height()) {
14252  if (x>=0 && x<width()) {
14253  const float w1 = (1 - dx)*(1 - dy)*(1 - dz), w2 = is_added?1:(1 - w1);
14254  (*this)(x,y,z,c) = (T)(w1*value + w2*(*this)(x,y,z,c));
14255  }
14256  if (nx>=0 && nx<width()) {
14257  const float w1 = dx*(1 - dy)*(1 - dz), w2 = is_added?1:(1 - w1);
14258  (*this)(nx,y,z,c) = (T)(w1*value + w2*(*this)(nx,y,z,c));
14259  }
14260  }
14261  if (ny>=0 && ny<height()) {
14262  if (x>=0 && x<width()) {
14263  const float w1 = (1 - dx)*dy*(1 - dz), w2 = is_added?1:(1 - w1);
14264  (*this)(x,ny,z,c) = (T)(w1*value + w2*(*this)(x,ny,z,c));
14265  }
14266  if (nx>=0 && nx<width()) {
14267  const float w1 = dx*dy*(1 - dz), w2 = is_added?1:(1 - w1);
14268  (*this)(nx,ny,z,c) = (T)(w1*value + w2*(*this)(nx,ny,z,c));
14269  }
14270  }
14271  }
14272  if (nz>=0 && nz<depth()) {
14273  if (y>=0 && y<height()) {
14274  if (x>=0 && x<width()) {
14275  const float w1 = (1 - dx)*(1 - dy)*dz, w2 = is_added?1:(1 - w1);
14276  (*this)(x,y,nz,c) = (T)(w1*value + w2*(*this)(x,y,nz,c));
14277  }
14278  if (nx>=0 && nx<width()) {
14279  const float w1 = dx*(1 - dy)*dz, w2 = is_added?1:(1 - w1);
14280  (*this)(nx,y,nz,c) = (T)(w1*value + w2*(*this)(nx,y,nz,c));
14281  }
14282  }
14283  if (ny>=0 && ny<height()) {
14284  if (x>=0 && x<width()) {
14285  const float w1 = (1 - dx)*dy*dz, w2 = is_added?1:(1 - w1);
14286  (*this)(x,ny,nz,c) = (T)(w1*value + w2*(*this)(x,ny,nz,c));
14287  }
14288  if (nx>=0 && nx<width()) {
14289  const float w1 = dx*dy*dz, w2 = is_added?1:(1 - w1);
14290  (*this)(nx,ny,nz,c) = (T)(w1*value + w2*(*this)(nx,ny,nz,c));
14291  }
14292  }
14293  }
14294  }
14295  return *this;
14296  }
14297 
14299 
14313  CImg<charT> value_string(const char separator=',', const unsigned int max_size=0,
14314  const char *const format=0) const {
14315  if (is_empty() || max_size==1) return CImg<charT>(1,1,1,1,0);
14316  CImgList<charT> items;
14317  CImg<charT> s_item(256); *s_item = 0;
14318  const T *ptrs = _data;
14319  unsigned int string_size = 0;
14320  const char *const _format = format?format:cimg::type<T>::format();
14321  for (ulongT off = 0, siz = size(); off<siz && (!max_size || string_size<max_size); ++off) {
14322  const unsigned int printed_size = 1U + cimg_snprintf(s_item,s_item._width,_format,
14323  cimg::type<T>::format(*(ptrs++)));
14324  CImg<charT> item(s_item._data,printed_size);
14325  item[printed_size - 1] = separator;
14326  item.move_to(items);
14327  if (max_size) string_size+=printed_size;
14328  }
14329  CImg<charT> res;
14330  (items>'x').move_to(res);
14331  if (max_size && res._width>=max_size) res.crop(0,max_size - 1);
14332  res.back() = 0;
14333  return res;
14334  }
14335 
14337  //-------------------------------------
14338  //
14340 
14341  //-------------------------------------
14342 
14344 
14351  bool is_shared() const {
14352  return _is_shared;
14353  }
14354 
14356 
14360  bool is_empty() const {
14361  return !(_data && _width && _height && _depth && _spectrum);
14362  }
14363 
14365 
14368  bool is_inf() const {
14369  if (cimg::type<T>::is_float()) cimg_for(*this,p,T) if (cimg::type<T>::is_inf((float)*p)) return true;
14370  return false;
14371  }
14372 
14374 
14377  bool is_nan() const {
14378  if (cimg::type<T>::is_float()) cimg_for(*this,p,T) if (cimg::type<T>::is_nan((float)*p)) return true;
14379  return false;
14380  }
14381 
14383  bool is_sameX(const unsigned int size_x) const {
14384  return _width==size_x;
14385  }
14386 
14388  template<typename t>
14389  bool is_sameX(const CImg<t>& img) const {
14390  return is_sameX(img._width);
14391  }
14392 
14394  bool is_sameX(const CImgDisplay& disp) const {
14395  return is_sameX(disp._width);
14396  }
14397 
14399  bool is_sameY(const unsigned int size_y) const {
14400  return _height==size_y;
14401  }
14402 
14404  template<typename t>
14405  bool is_sameY(const CImg<t>& img) const {
14406  return is_sameY(img._height);
14407  }
14408 
14410  bool is_sameY(const CImgDisplay& disp) const {
14411  return is_sameY(disp._height);
14412  }
14413 
14415  bool is_sameZ(const unsigned int size_z) const {
14416  return _depth==size_z;
14417  }
14418 
14420  template<typename t>
14421  bool is_sameZ(const CImg<t>& img) const {
14422  return is_sameZ(img._depth);
14423  }
14424 
14426  bool is_sameC(const unsigned int size_c) const {
14427  return _spectrum==size_c;
14428  }
14429 
14431  template<typename t>
14432  bool is_sameC(const CImg<t>& img) const {
14433  return is_sameC(img._spectrum);
14434  }
14435 
14437 
14440  bool is_sameXY(const unsigned int size_x, const unsigned int size_y) const {
14441  return _width==size_x && _height==size_y;
14442  }
14443 
14445 
14448  template<typename t>
14449  bool is_sameXY(const CImg<t>& img) const {
14450  return is_sameXY(img._width,img._height);
14451  }
14452 
14454 
14457  bool is_sameXY(const CImgDisplay& disp) const {
14458  return is_sameXY(disp._width,disp._height);
14459  }
14460 
14462 
14465  bool is_sameXZ(const unsigned int size_x, const unsigned int size_z) const {
14466  return _width==size_x && _depth==size_z;
14467  }
14468 
14470 
14473  template<typename t>
14474  bool is_sameXZ(const CImg<t>& img) const {
14475  return is_sameXZ(img._width,img._depth);
14476  }
14477 
14479 
14482  bool is_sameXC(const unsigned int size_x, const unsigned int size_c) const {
14483  return _width==size_x && _spectrum==size_c;
14484  }
14485 
14487 
14490  template<typename t>
14491  bool is_sameXC(const CImg<t>& img) const {
14492  return is_sameXC(img._width,img._spectrum);
14493  }
14494 
14496 
14499  bool is_sameYZ(const unsigned int size_y, const unsigned int size_z) const {
14500  return _height==size_y && _depth==size_z;
14501  }
14502 
14504 
14507  template<typename t>
14508  bool is_sameYZ(const CImg<t>& img) const {
14509  return is_sameYZ(img._height,img._depth);
14510  }
14511 
14513 
14516  bool is_sameYC(const unsigned int size_y, const unsigned int size_c) const {
14517  return _height==size_y && _spectrum==size_c;
14518  }
14519 
14521 
14524  template<typename t>
14525  bool is_sameYC(const CImg<t>& img) const {
14526  return is_sameYC(img._height,img._spectrum);
14527  }
14528 
14530 
14533  bool is_sameZC(const unsigned int size_z, const unsigned int size_c) const {
14534  return _depth==size_z && _spectrum==size_c;
14535  }
14536 
14538 
14541  template<typename t>
14542  bool is_sameZC(const CImg<t>& img) const {
14543  return is_sameZC(img._depth,img._spectrum);
14544  }
14545 
14547 
14550  bool is_sameXYZ(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z) const {
14551  return is_sameXY(size_x,size_y) && _depth==size_z;
14552  }
14553 
14555 
14558  template<typename t>
14559  bool is_sameXYZ(const CImg<t>& img) const {
14560  return is_sameXYZ(img._width,img._height,img._depth);
14561  }
14562 
14564 
14567  bool is_sameXYC(const unsigned int size_x, const unsigned int size_y, const unsigned int size_c) const {
14568  return is_sameXY(size_x,size_y) && _spectrum==size_c;
14569  }
14570 
14572 
14575  template<typename t>
14576  bool is_sameXYC(const CImg<t>& img) const {
14577  return is_sameXYC(img._width,img._height,img._spectrum);
14578  }
14579 
14581 
14584  bool is_sameXZC(const unsigned int size_x, const unsigned int size_z, const unsigned int size_c) const {
14585  return is_sameXZ(size_x,size_z) && _spectrum==size_c;
14586  }
14587 
14589 
14592  template<typename t>
14593  bool is_sameXZC(const CImg<t>& img) const {
14594  return is_sameXZC(img._width,img._depth,img._spectrum);
14595  }
14596 
14598 
14601  bool is_sameYZC(const unsigned int size_y, const unsigned int size_z, const unsigned int size_c) const {
14602  return is_sameYZ(size_y,size_z) && _spectrum==size_c;
14603  }
14604 
14606 
14609  template<typename t>
14610  bool is_sameYZC(const CImg<t>& img) const {
14611  return is_sameYZC(img._height,img._depth,img._spectrum);
14612  }
14613 
14615 
14619  bool is_sameXYZC(const unsigned int size_x, const unsigned int size_y,
14620  const unsigned int size_z, const unsigned int size_c) const {
14621  return is_sameXYZ(size_x,size_y,size_z) && _spectrum==size_c;
14622  }
14623 
14625 
14628  template<typename t>
14629  bool is_sameXYZC(const CImg<t>& img) const {
14630  return is_sameXYZC(img._width,img._height,img._depth,img._spectrum);
14631  }
14632 
14634 
14649  bool containsXYZC(const int x, const int y=0, const int z=0, const int c=0) const {
14650  return !is_empty() && x>=0 && x<width() && y>=0 && y<height() && z>=0 && z<depth() && c>=0 && c<spectrum();
14651  }
14652 
14654 
14674  template<typename t>
14675  bool contains(const T& pixel, t& x, t& y, t& z, t& c) const {
14676  const ulongT wh = (ulongT)_width*_height, whd = wh*_depth, siz = whd*_spectrum;
14677  const T *const ppixel = &pixel;
14678  if (is_empty() || ppixel<_data || ppixel>=_data + siz) return false;
14679  ulongT off = (ulongT)(ppixel - _data);
14680  const ulongT nc = off/whd;
14681  off%=whd;
14682  const ulongT nz = off/wh;
14683  off%=wh;
14684  const ulongT ny = off/_width, nx = off%_width;
14685  x = (t)nx; y = (t)ny; z = (t)nz; c = (t)nc;
14686  return true;
14687  }
14688 
14690 
14693  template<typename t>
14694  bool contains(const T& pixel, t& x, t& y, t& z) const {
14695  const ulongT wh = (ulongT)_width*_height, whd = wh*_depth, siz = whd*_spectrum;
14696  const T *const ppixel = &pixel;
14697  if (is_empty() || ppixel<_data || ppixel>=_data + siz) return false;
14698  ulongT off = ((ulongT)(ppixel - _data))%whd;
14699  const ulongT nz = off/wh;
14700  off%=wh;
14701  const ulongT ny = off/_width, nx = off%_width;
14702  x = (t)nx; y = (t)ny; z = (t)nz;
14703  return true;
14704  }
14705 
14707 
14710  template<typename t>
14711  bool contains(const T& pixel, t& x, t& y) const {
14712  const ulongT wh = (ulongT)_width*_height, siz = wh*_depth*_spectrum;
14713  const T *const ppixel = &pixel;
14714  if (is_empty() || ppixel<_data || ppixel>=_data + siz) return false;
14715  ulongT off = ((unsigned int)(ppixel - _data))%wh;
14716  const ulongT ny = off/_width, nx = off%_width;
14717  x = (t)nx; y = (t)ny;
14718  return true;
14719  }
14720 
14722 
14725  template<typename t>
14726  bool contains(const T& pixel, t& x) const {
14727  const T *const ppixel = &pixel;
14728  if (is_empty() || ppixel<_data || ppixel>=_data + size()) return false;
14729  x = (t)(((ulongT)(ppixel - _data))%_width);
14730  return true;
14731  }
14732 
14734 
14737  bool contains(const T& pixel) const {
14738  const T *const ppixel = &pixel;
14739  return !is_empty() && ppixel>=_data && ppixel<_data + size();
14740  }
14741 
14743 
14761  template<typename t>
14762  bool is_overlapped(const CImg<t>& img) const {
14763  const ulongT csiz = size(), isiz = img.size();
14764  return !((void*)(_data + csiz)<=(void*)img._data || (void*)_data>=(void*)(img._data + isiz));
14765  }
14766 
14768 
14781  template<typename tp, typename tc, typename to>
14782  bool is_object3d(const CImgList<tp>& primitives,
14783  const CImgList<tc>& colors,
14784  const to& opacities,
14785  const bool full_check=true,
14786  char *const error_message=0) const {
14787  if (error_message) *error_message = 0;
14788 
14789  // Check consistency for the particular case of an empty 3d object.
14790  if (is_empty()) {
14791  if (primitives || colors || opacities) {
14792  if (error_message) cimg_sprintf(error_message,
14793  "3d object (%u,%u) defines no vertices but %u primitives, "
14794  "%u colors and %lu opacities",
14795  _width,primitives._width,primitives._width,
14796  colors._width,(unsigned long)opacities.size());
14797  return false;
14798  }
14799  return true;
14800  }
14801 
14802  // Check consistency of vertices.
14803  if (_height!=3 || _depth>1 || _spectrum>1) { // Check vertices dimensions.
14804  if (error_message) cimg_sprintf(error_message,
14805  "3d object (%u,%u) has invalid vertex dimensions (%u,%u,%u,%u)",
14806  _width,primitives._width,_width,_height,_depth,_spectrum);
14807  return false;
14808  }
14809  if (colors._width>primitives._width + 1) {
14810  if (error_message) cimg_sprintf(error_message,
14811  "3d object (%u,%u) defines %u colors",
14812  _width,primitives._width,colors._width);
14813  return false;
14814  }
14815  if (opacities.size()>primitives._width) {
14816  if (error_message) cimg_sprintf(error_message,
14817  "3d object (%u,%u) defines %lu opacities",
14818  _width,primitives._width,(unsigned long)opacities.size());
14819  return false;
14820  }
14821  if (!full_check) return true;
14822 
14823  // Check consistency of primitives.
14824  cimglist_for(primitives,l) {
14825  const CImg<tp>& primitive = primitives[l];
14826  const unsigned int psiz = (unsigned int)primitive.size();
14827  switch (psiz) {
14828  case 1 : { // Point.
14829  const unsigned int i0 = (unsigned int)primitive(0);
14830  if (i0>=_width) {
14831  if (error_message) cimg_sprintf(error_message,
14832  "3d object (%u,%u) refers to invalid vertex indice %u in "
14833  "point primitive [%u]",
14834  _width,primitives._width,i0,l);
14835  return false;
14836  }
14837  } break;
14838  case 5 : { // Sphere.
14839  const unsigned int
14840  i0 = (unsigned int)primitive(0),
14841  i1 = (unsigned int)primitive(1);
14842  if (i0>=_width || i1>=_width) {
14843  if (error_message) cimg_sprintf(error_message,
14844  "3d object (%u,%u) refers to invalid vertex indices (%u,%u) in "
14845  "sphere primitive [%u]",
14846  _width,primitives._width,i0,i1,l);
14847  return false;
14848  }
14849  } break;
14850  case 2 : // Segment.
14851  case 6 : {
14852  const unsigned int
14853  i0 = (unsigned int)primitive(0),
14854  i1 = (unsigned int)primitive(1);
14855  if (i0>=_width || i1>=_width) {
14856  if (error_message) cimg_sprintf(error_message,
14857  "3d object (%u,%u) refers to invalid vertex indices (%u,%u) in "
14858  "segment primitive [%u]",
14859  _width,primitives._width,i0,i1,l);
14860  return false;
14861  }
14862  } break;
14863  case 3 : // Triangle.
14864  case 9 : {
14865  const unsigned int
14866  i0 = (unsigned int)primitive(0),
14867  i1 = (unsigned int)primitive(1),
14868  i2 = (unsigned int)primitive(2);
14869  if (i0>=_width || i1>=_width || i2>=_width) {
14870  if (error_message) cimg_sprintf(error_message,
14871  "3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u) in "
14872  "triangle primitive [%u]",
14873  _width,primitives._width,i0,i1,i2,l);
14874  return false;
14875  }
14876  } break;
14877  case 4 : // Quadrangle.
14878  case 12 : {
14879  const unsigned int
14880  i0 = (unsigned int)primitive(0),
14881  i1 = (unsigned int)primitive(1),
14882  i2 = (unsigned int)primitive(2),
14883  i3 = (unsigned int)primitive(3);
14884  if (i0>=_width || i1>=_width || i2>=_width || i3>=_width) {
14885  if (error_message) cimg_sprintf(error_message,
14886  "3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in "
14887  "quadrangle primitive [%u]",
14888  _width,primitives._width,i0,i1,i2,i3,l);
14889  return false;
14890  }
14891  } break;
14892  default :
14893  if (error_message) cimg_sprintf(error_message,
14894  "3d object (%u,%u) defines an invalid primitive [%u] of size %u",
14895  _width,primitives._width,l,(unsigned int)psiz);
14896  return false;
14897  }
14898  }
14899 
14900  // Check consistency of colors.
14901  cimglist_for(colors,c) {
14902  const CImg<tc>& color = colors[c];
14903  if (!color) {
14904  if (error_message) cimg_sprintf(error_message,
14905  "3d object (%u,%u) defines no color for primitive [%u]",
14906  _width,primitives._width,c);
14907  return false;
14908  }
14909  }
14910 
14911  // Check consistency of light texture.
14912  if (colors._width>primitives._width) {
14913  const CImg<tc> &light = colors.back();
14914  if (!light || light._depth>1) {
14915  if (error_message) cimg_sprintf(error_message,
14916  "3d object (%u,%u) defines an invalid light texture (%u,%u,%u,%u)",
14917  _width,primitives._width,light._width,
14918  light._height,light._depth,light._spectrum);
14919  return false;
14920  }
14921  }
14922 
14923  return true;
14924  }
14925 
14927 
14936  bool is_CImg3d(const bool full_check=true, char *const error_message=0) const {
14937  if (error_message) *error_message = 0;
14938 
14939  // Check instance dimension and header.
14940  if (_width!=1 || _height<8 || _depth!=1 || _spectrum!=1) {
14941  if (error_message) cimg_sprintf(error_message,
14942  "CImg3d has invalid dimensions (%u,%u,%u,%u)",
14943  _width,_height,_depth,_spectrum);
14944  return false;
14945  }
14946  const T *ptrs = _data, *const ptre = end();
14947  if (!_is_CImg3d(*(ptrs++),'C') || !_is_CImg3d(*(ptrs++),'I') || !_is_CImg3d(*(ptrs++),'m') ||
14948  !_is_CImg3d(*(ptrs++),'g') || !_is_CImg3d(*(ptrs++),'3') || !_is_CImg3d(*(ptrs++),'d')) {
14949  if (error_message) cimg_sprintf(error_message,
14950  "CImg3d header not found");
14951  return false;
14952  }
14953  const unsigned int
14954  nb_points = cimg::float2uint((float)*(ptrs++)),
14955  nb_primitives = cimg::float2uint((float)*(ptrs++));
14956 
14957  // Check consistency of number of vertices / primitives.
14958  if (!full_check) {
14959  const ulongT minimal_size = 8UL + 3*nb_points + 6*nb_primitives;
14960  if (_data + minimal_size>ptre) {
14961  if (error_message) cimg_sprintf(error_message,
14962  "CImg3d (%u,%u) has only %lu values, while at least %lu values were expected",
14963  nb_points,nb_primitives,(unsigned long)size(),(unsigned long)minimal_size);
14964  return false;
14965  }
14966  }
14967 
14968  // Check consistency of vertex data.
14969  if (!nb_points) {
14970  if (nb_primitives) {
14971  if (error_message) cimg_sprintf(error_message,
14972  "CImg3d (%u,%u) defines no vertices but %u primitives",
14973  nb_points,nb_primitives,nb_primitives);
14974  return false;
14975  }
14976  if (ptrs!=ptre) {
14977  if (error_message) cimg_sprintf(error_message,
14978  "CImg3d (%u,%u) is an empty object but contains %u value%s "
14979  "more than expected",
14980  nb_points,nb_primitives,(unsigned int)(ptre - ptrs),(ptre - ptrs)>1?"s":"");
14981  return false;
14982  }
14983  return true;
14984  }
14985  if (ptrs + 3*nb_points>ptre) {
14986  if (error_message) cimg_sprintf(error_message,
14987  "CImg3d (%u,%u) defines only %u vertices data",
14988  nb_points,nb_primitives,(unsigned int)(ptre - ptrs)/3);
14989  return false;
14990  }
14991  ptrs+=3*nb_points;
14992 
14993  // Check consistency of primitive data.
14994  if (ptrs==ptre) {
14995  if (error_message) cimg_sprintf(error_message,
14996  "CImg3d (%u,%u) defines %u vertices but no primitive",
14997  nb_points,nb_primitives,nb_points);
14998  return false;
14999  }
15000 
15001  if (!full_check) return true;
15002 
15003  for (unsigned int p = 0; p<nb_primitives; ++p) {
15004  const unsigned int nb_inds = (unsigned int)*(ptrs++);
15005  switch (nb_inds) {
15006  case 1 : { // Point.
15007  const unsigned int i0 = cimg::float2uint((float)*(ptrs++));
15008  if (i0>=nb_points) {
15009  if (error_message) cimg_sprintf(error_message,
15010  "CImg3d (%u,%u) refers to invalid vertex indice %u in point primitive [%u]",
15011  nb_points,nb_primitives,i0,p);
15012  return false;
15013  }
15014  } break;
15015  case 5 : { // Sphere.
15016  const unsigned int
15017  i0 = cimg::float2uint((float)*(ptrs++)),
15018  i1 = cimg::float2uint((float)*(ptrs++));
15019  ptrs+=3;
15020  if (i0>=nb_points || i1>=nb_points) {
15021  if (error_message) cimg_sprintf(error_message,
15022  "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in "
15023  "sphere primitive [%u]",
15024  nb_points,nb_primitives,i0,i1,p);
15025  return false;
15026  }
15027  } break;
15028  case 2 : case 6 : { // Segment.
15029  const unsigned int
15030  i0 = cimg::float2uint((float)*(ptrs++)),
15031  i1 = cimg::float2uint((float)*(ptrs++));
15032  if (nb_inds==6) ptrs+=4;
15033  if (i0>=nb_points || i1>=nb_points) {
15034  if (error_message) cimg_sprintf(error_message,
15035  "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in "
15036  "segment primitive [%u]",
15037  nb_points,nb_primitives,i0,i1,p);
15038  return false;
15039  }
15040  } break;
15041  case 3 : case 9 : { // Triangle.
15042  const unsigned int
15043  i0 = cimg::float2uint((float)*(ptrs++)),
15044  i1 = cimg::float2uint((float)*(ptrs++)),
15045  i2 = cimg::float2uint((float)*(ptrs++));
15046  if (nb_inds==9) ptrs+=6;
15047  if (i0>=nb_points || i1>=nb_points || i2>=nb_points) {
15048  if (error_message) cimg_sprintf(error_message,
15049  "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u) in "
15050  "triangle primitive [%u]",
15051  nb_points,nb_primitives,i0,i1,i2,p);
15052  return false;
15053  }
15054  } break;
15055  case 4 : case 12 : { // Quadrangle.
15056  const unsigned int
15057  i0 = cimg::float2uint((float)*(ptrs++)),
15058  i1 = cimg::float2uint((float)*(ptrs++)),
15059  i2 = cimg::float2uint((float)*(ptrs++)),
15060  i3 = cimg::float2uint((float)*(ptrs++));
15061  if (nb_inds==12) ptrs+=8;
15062  if (i0>=nb_points || i1>=nb_points || i2>=nb_points || i3>=nb_points) {
15063  if (error_message) cimg_sprintf(error_message,
15064  "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in "
15065  "quadrangle primitive [%u]",
15066  nb_points,nb_primitives,i0,i1,i2,i3,p);
15067  return false;
15068  }
15069  } break;
15070  default :
15071  if (error_message) cimg_sprintf(error_message,
15072  "CImg3d (%u,%u) defines an invalid primitive [%u] of size %u",
15073  nb_points,nb_primitives,p,nb_inds);
15074  return false;
15075  }
15076  if (ptrs>ptre) {
15077  if (error_message) cimg_sprintf(error_message,
15078  "CImg3d (%u,%u) has incomplete primitive data for primitive [%u], "
15079  "%u values missing",
15080  nb_points,nb_primitives,p,(unsigned int)(ptrs - ptre));
15081  return false;
15082  }
15083  }
15084 
15085  // Check consistency of color data.
15086  if (ptrs==ptre) {
15087  if (error_message) cimg_sprintf(error_message,
15088  "CImg3d (%u,%u) defines no color/texture data",
15089  nb_points,nb_primitives);
15090  return false;
15091  }
15092  for (unsigned int c = 0; c<nb_primitives; ++c) {
15093  if (*(ptrs++)!=(T)-128) ptrs+=2;
15094  else if ((ptrs+=3)<ptre) {
15095  const unsigned int
15096  w = (unsigned int)*(ptrs - 3),
15097  h = (unsigned int)*(ptrs - 2),
15098  s = (unsigned int)*(ptrs - 1);
15099  if (!h && !s) {
15100  if (w>=c) {
15101  if (error_message) cimg_sprintf(error_message,
15102  "CImg3d (%u,%u) refers to invalid shared sprite/texture indice %u "
15103  "for primitive [%u]",
15104  nb_points,nb_primitives,w,c);
15105  return false;
15106  }
15107  } else ptrs+=w*h*s;
15108  }
15109  if (ptrs>ptre) {
15110  if (error_message) cimg_sprintf(error_message,
15111  "CImg3d (%u,%u) has incomplete color/texture data for primitive [%u], "
15112  "%u values missing",
15113  nb_points,nb_primitives,c,(unsigned int)(ptrs - ptre));
15114  return false;
15115  }
15116  }
15117 
15118  // Check consistency of opacity data.
15119  if (ptrs==ptre) {
15120  if (error_message) cimg_sprintf(error_message,
15121  "CImg3d (%u,%u) defines no opacity data",
15122  nb_points,nb_primitives);
15123  return false;
15124  }
15125  for (unsigned int o = 0; o<nb_primitives; ++o) {
15126  if (*(ptrs++)==(T)-128 && (ptrs+=3)<ptre) {
15127  const unsigned int
15128  w = (unsigned int)*(ptrs - 3),
15129  h = (unsigned int)*(ptrs - 2),
15130  s = (unsigned int)*(ptrs - 1);
15131  if (!h && !s) {
15132  if (w>=o) {
15133  if (error_message) cimg_sprintf(error_message,
15134  "CImg3d (%u,%u) refers to invalid shared opacity indice %u "
15135  "for primitive [%u]",
15136  nb_points,nb_primitives,w,o);
15137  return false;
15138  }
15139  } else ptrs+=w*h*s;
15140  }
15141  if (ptrs>ptre) {
15142  if (error_message) cimg_sprintf(error_message,
15143  "CImg3d (%u,%u) has incomplete opacity data for primitive [%u]",
15144  nb_points,nb_primitives,o);
15145  return false;
15146  }
15147  }
15148 
15149  // Check end of data.
15150  if (ptrs<ptre) {
15151  if (error_message) cimg_sprintf(error_message,
15152  "CImg3d (%u,%u) contains %u value%s more than expected",
15153  nb_points,nb_primitives,(unsigned int)(ptre - ptrs),(ptre - ptrs)>1?"s":"");
15154  return false;
15155  }
15156  return true;
15157  }
15158 
15159  static bool _is_CImg3d(const T val, const char c) {
15160  return val>=(T)c && val<(T)(c + 1);
15161  }
15162 
15164  //-------------------------------------
15165  //
15167 
15168  //-------------------------------------
15169 
15170  // Define the math formula parser/compiler and expression evaluator.
15172  CImg<doubleT> mem;
15173  CImg<intT> memtype;
15174  CImgList<ulongT> _code, &code, code_init, code_end;
15175  CImg<ulongT> opcode;
15176  const CImg<ulongT> *p_code_end, *p_code;
15177  const CImg<ulongT> *const p_break;
15178 
15179  CImg<charT> expr, pexpr;
15180  const CImg<T>& imgin;
15181  const CImgList<T>& listin;
15182  CImg<T> &imgout;
15183  CImgList<T>& listout;
15184 
15185  CImg<doubleT> _img_stats, &img_stats, constcache_vals;
15186  CImgList<doubleT> _list_stats, &list_stats, _list_median, &list_median;
15187  CImg<uintT> mem_img_stats, constcache_inds;
15188 
15189  CImg<uintT> level, variable_pos, reserved_label;
15190  CImgList<charT> variable_def, macro_def, macro_body;
15191  CImgList<boolT> macro_body_is_string;
15192  char *user_macro;
15193 
15194  unsigned int mempos, mem_img_median, debug_indent, result_dim, break_type, constcache_size;
15195  bool is_parallelizable, is_fill, need_input_copy;
15196  double *result;
15197  const char *const calling_function, *s_op, *ss_op;
15198  typedef double (*mp_func)(_cimg_math_parser&);
15199 
15200 #define _cimg_mp_is_constant(arg) (memtype[arg]==1) // Is constant value?
15201 #define _cimg_mp_is_scalar(arg) (memtype[arg]<2) // Is scalar value?
15202 #define _cimg_mp_is_comp(arg) (!memtype[arg]) // Is computation value?
15203 #define _cimg_mp_is_variable(arg) (memtype[arg]==-1) // Is scalar variable?
15204 #define _cimg_mp_is_vector(arg) (memtype[arg]>1) // Is vector?
15205 #define _cimg_mp_size(arg) (_cimg_mp_is_scalar(arg)?0U:(unsigned int)memtype[arg] - 1) // Size (0=scalar, N>0=vectorN)
15206 #define _cimg_mp_calling_function calling_function_s()._data
15207 #define _cimg_mp_op(s) s_op = s; ss_op = ss
15208 #define _cimg_mp_check_type(arg,n_arg,mode,N) check_type(arg,n_arg,mode,N,ss,se,saved_char)
15209 #define _cimg_mp_check_constant(arg,n_arg,mode) check_constant(arg,n_arg,mode,ss,se,saved_char)
15210 #define _cimg_mp_check_matrix_square(arg,n_arg) check_matrix_square(arg,n_arg,ss,se,saved_char)
15211 #define _cimg_mp_check_vector0(dim) check_vector0(dim,ss,se,saved_char)
15212 #define _cimg_mp_check_list(is_out) check_list(is_out,ss,se,saved_char)
15213 #define _cimg_mp_defunc(mp) (*(mp_func)(*(mp).opcode))(mp)
15214 #define _cimg_mp_return(x) { *se = saved_char; s_op = previous_s_op; ss_op = previous_ss_op; return x; }
15215 #define _cimg_mp_return_nan() _cimg_mp_return(_cimg_mp_slot_nan)
15216 #define _cimg_mp_constant(val) _cimg_mp_return(constant((double)(val)))
15217 #define _cimg_mp_scalar0(op) _cimg_mp_return(scalar0(op))
15218 #define _cimg_mp_scalar1(op,i1) _cimg_mp_return(scalar1(op,i1))
15219 #define _cimg_mp_scalar2(op,i1,i2) _cimg_mp_return(scalar2(op,i1,i2))
15220 #define _cimg_mp_scalar3(op,i1,i2,i3) _cimg_mp_return(scalar3(op,i1,i2,i3))
15221 #define _cimg_mp_scalar4(op,i1,i2,i3,i4) _cimg_mp_return(scalar4(op,i1,i2,i3,i4))
15222 #define _cimg_mp_scalar5(op,i1,i2,i3,i4,i5) _cimg_mp_return(scalar5(op,i1,i2,i3,i4,i5))
15223 #define _cimg_mp_scalar6(op,i1,i2,i3,i4,i5,i6) _cimg_mp_return(scalar6(op,i1,i2,i3,i4,i5,i6))
15224 #define _cimg_mp_scalar7(op,i1,i2,i3,i4,i5,i6,i7) _cimg_mp_return(scalar7(op,i1,i2,i3,i4,i5,i6,i7))
15225 #define _cimg_mp_vector1_v(op,i1) _cimg_mp_return(vector1_v(op,i1))
15226 #define _cimg_mp_vector2_sv(op,i1,i2) _cimg_mp_return(vector2_sv(op,i1,i2))
15227 #define _cimg_mp_vector2_vs(op,i1,i2) _cimg_mp_return(vector2_vs(op,i1,i2))
15228 #define _cimg_mp_vector2_vv(op,i1,i2) _cimg_mp_return(vector2_vv(op,i1,i2))
15229 #define _cimg_mp_vector3_vss(op,i1,i2,i3) _cimg_mp_return(vector3_vss(op,i1,i2,i3))
15230 
15231  // Constructors.
15232  _cimg_math_parser(const char *const expression, const char *const funcname=0,
15233  const CImg<T>& img_input=CImg<T>::const_empty(), CImg<T> *const img_output=0,
15234  const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0,
15235  const bool _is_fill=false):
15236  code(_code),p_break((CImg<ulongT>*)0 - 2),
15237  imgin(img_input),listin(list_inputs?*list_inputs:CImgList<T>::const_empty()),
15238  imgout(img_output?*img_output:CImg<T>::empty()),listout(list_outputs?*list_outputs:CImgList<T>::empty()),
15239  img_stats(_img_stats),list_stats(_list_stats),list_median(_list_median),user_macro(0),
15240  mem_img_median(~0U),debug_indent(0),result_dim(0),break_type(0),constcache_size(0),
15241  is_parallelizable(true),is_fill(_is_fill),need_input_copy(false),
15242  calling_function(funcname?funcname:"cimg_math_parser") {
15243  if (!expression || !*expression)
15244  throw CImgArgumentException("[" cimg_appname "_math_parser] "
15245  "CImg<%s>::%s: Empty expression.",
15246  pixel_type(),_cimg_mp_calling_function);
15247  const char *_expression = expression;
15248  while (*_expression && ((signed char)*_expression<=' ' || *_expression==';')) ++_expression;
15249  CImg<charT>::string(_expression).move_to(expr);
15250  char *ps = &expr.back() - 1;
15251  while (ps>expr._data && ((signed char)*ps<=' ' || *ps==';')) --ps;
15252  *(++ps) = 0; expr._width = (unsigned int)(ps - expr._data + 1);
15253 
15254  // Ease the retrieval of previous non-space characters afterwards.
15255  pexpr.assign(expr._width);
15256  char c, *pe = pexpr._data;
15257  for (ps = expr._data, c = ' '; *ps; ++ps) {
15258  if ((signed char)*ps>' ') c = *ps; else *ps = ' ';
15259  *(pe++) = c;
15260  }
15261  *pe = 0;
15262  level = get_level(expr);
15263 
15264  // Init constant values.
15265 #define _cimg_mp_interpolation (reserved_label[29]!=~0U?reserved_label[29]:0)
15266 #define _cimg_mp_boundary (reserved_label[30]!=~0U?reserved_label[30]:0)
15267 #define _cimg_mp_slot_nan 29
15268 #define _cimg_mp_slot_x 30
15269 #define _cimg_mp_slot_y 31
15270 #define _cimg_mp_slot_z 32
15271 #define _cimg_mp_slot_c 33
15272 
15273  mem.assign(96);
15274  for (unsigned int i = 0; i<=10; ++i) mem[i] = (double)i; // mem[0-10] = 0...10
15275  for (unsigned int i = 1; i<=5; ++i) mem[i + 10] = -(double)i; // mem[11-15] = -1...-5
15276  mem[16] = 0.5;
15277  mem[17] = 0; // thread_id
15278  mem[18] = (double)imgin._width; // w
15279  mem[19] = (double)imgin._height; // h
15280  mem[20] = (double)imgin._depth; // d
15281  mem[21] = (double)imgin._spectrum; // s
15282  mem[22] = (double)imgin._is_shared; // r
15283  mem[23] = (double)imgin._width*imgin._height; // wh
15284  mem[24] = (double)imgin._width*imgin._height*imgin._depth; // whd
15285  mem[25] = (double)imgin._width*imgin._height*imgin._depth*imgin._spectrum; // whds
15286  mem[26] = (double)listin._width; // l
15287  mem[27] = std::exp(1.0); // e
15288  mem[28] = cimg::PI; // pi
15289  mem[_cimg_mp_slot_nan] = cimg::type<double>::nan(); // nan
15290 
15291  // Set value property :
15292  // { -2 = other | -1 = variable | 0 = computation value |
15293  // 1 = compile-time constant | N>1 = constant ptr to vector[N-1] }.
15294  memtype.assign(mem._width,1,1,1,0);
15295  for (unsigned int i = 0; i<_cimg_mp_slot_x; ++i) memtype[i] = 1;
15296  memtype[17] = 0;
15297  memtype[_cimg_mp_slot_x] = memtype[_cimg_mp_slot_y] = memtype[_cimg_mp_slot_z] = memtype[_cimg_mp_slot_c] = -2;
15298  mempos = _cimg_mp_slot_c + 1;
15299  variable_pos.assign(8);
15300 
15301  reserved_label.assign(128,1,1,1,~0U);
15302  // reserved_label[4-28] are used to store these two-char variables:
15303  // [0] = wh, [1] = whd, [2] = whds, [3] = pi, [4] = im, [5] = iM, [6] = ia, [7] = iv,
15304  // [8] = is, [9] = ip, [10] = ic, [11] = xm, [12] = ym, [13] = zm, [14] = cm, [15] = xM,
15305  // [16] = yM, [17] = zM, [18]=cM, [19]=i0...[28]=i9, [29] = interpolation, [30] = boundary
15306 
15307  // Compile expression into a serie of opcodes.
15308  s_op = ""; ss_op = expr._data;
15309  const unsigned int ind_result = compile(expr._data,expr._data + expr._width - 1,0,0,false);
15310  if (!_cimg_mp_is_constant(ind_result)) {
15311  if (_cimg_mp_is_vector(ind_result))
15312  CImg<doubleT>(&mem[ind_result] + 1,_cimg_mp_size(ind_result),1,1,1,true).
15313  fill(cimg::type<double>::nan());
15314  else mem[ind_result] = cimg::type<double>::nan();
15315  }
15316 
15317  // Free resources used for compiling expression and prepare evaluation.
15318  result_dim = _cimg_mp_size(ind_result);
15319  if (mem._width>=256 && mem._width - mempos>=mem._width/2) mem.resize(mempos,1,1,1,-1);
15320  result = mem._data + ind_result;
15321  memtype.assign();
15322  constcache_vals.assign();
15323  constcache_inds.assign();
15324  level.assign();
15325  variable_pos.assign();
15326  reserved_label.assign();
15327  expr.assign();
15328  pexpr.assign();
15329  opcode.assign();
15330  opcode._is_shared = true;
15331 
15332  // Execute init() bloc if any specified.
15333  if (code_init) {
15334  mem[_cimg_mp_slot_x] = mem[_cimg_mp_slot_y] = mem[_cimg_mp_slot_z] = mem[_cimg_mp_slot_c] = 0;
15335  p_code_end = code_init.end();
15336  for (p_code = code_init; p_code<p_code_end; ++p_code) {
15337  opcode._data = p_code->_data;
15338  const ulongT target = opcode[1];
15339  mem[target] = _cimg_mp_defunc(*this);
15340  }
15341  }
15342  p_code_end = code.end();
15343  }
15344 
15345  _cimg_math_parser():
15346  code(_code),p_code_end(0),p_break((CImg<ulongT>*)0 - 2),
15348  imgout(CImg<T>::empty()),listout(CImgList<T>::empty()),
15349  img_stats(_img_stats),list_stats(_list_stats),list_median(_list_median),debug_indent(0),
15350  result_dim(0),break_type(0),constcache_size(0),is_parallelizable(true),is_fill(false),need_input_copy(false),
15351  calling_function(0) {
15352  mem.assign(1 + _cimg_mp_slot_c,1,1,1,0); // Allow to skip 'is_empty?' test in operator()()
15353  result = mem._data;
15354  }
15355 
15356  _cimg_math_parser(const _cimg_math_parser& mp):
15357  mem(mp.mem),code(mp.code),p_code_end(mp.p_code_end),p_break(mp.p_break),
15358  imgin(mp.imgin),listin(mp.listin),imgout(mp.imgout),listout(mp.listout),img_stats(mp.img_stats),
15359  list_stats(mp.list_stats),list_median(mp.list_median),debug_indent(0),result_dim(mp.result_dim),
15360  break_type(0),constcache_size(0),is_parallelizable(mp.is_parallelizable),is_fill(mp.is_fill),
15361  need_input_copy(mp.need_input_copy), result(mem._data + (mp.result - mp.mem._data)),calling_function(0) {
15362 #ifdef cimg_use_openmp
15363  mem[17] = omp_get_thread_num();
15364 #endif
15365  opcode.assign();
15366  opcode._is_shared = true;
15367  }
15368 
15369  // Count parentheses/brackets level of each character of the expression.
15370  CImg<uintT> get_level(CImg<charT>& expr) const {
15371  bool is_escaped = false, next_is_escaped = false;
15372  unsigned int mode = 0, next_mode = 0; // { 0=normal | 1=char-string | 2=vector-string
15373  CImg<uintT> res(expr._width - 1);
15374  unsigned int *pd = res._data;
15375  int level = 0;
15376  for (const char *ps = expr._data; *ps && level>=0; ++ps) {
15377  if (!is_escaped && !next_is_escaped && *ps=='\\') next_is_escaped = true;
15378  if (!is_escaped && *ps=='\'') { // Non-escaped character
15379  if (!mode && ps>expr._data && *(ps - 1)=='[') next_mode = mode = 2; // Start vector-string
15380  else if (mode==2 && *(ps + 1)==']') next_mode = !mode; // End vector-string
15381  else if (mode<2) next_mode = mode?(mode = 0):1; // Start/end char-string
15382  }
15383  *(pd++) = (unsigned int)(mode>=1 || is_escaped?level + (mode==1):
15384  *ps=='(' || *ps=='['?level++:
15385  *ps==')' || *ps==']'?--level:
15386  level);
15387  mode = next_mode;
15388  is_escaped = next_is_escaped;
15389  next_is_escaped = false;
15390  }
15391  if (mode) {
15392  cimg::strellipsize(expr,64);
15393  throw CImgArgumentException("[" cimg_appname "_math_parser] "
15394  "CImg<%s>::%s: Unterminated string literal, in expression '%s'.",
15395  pixel_type(),_cimg_mp_calling_function,
15396  expr._data);
15397  }
15398  if (level) {
15399  cimg::strellipsize(expr,64);
15400  throw CImgArgumentException("[" cimg_appname "_math_parser] "
15401  "CImg<%s>::%s: Unbalanced parentheses/brackets, in expression '%s'.",
15402  pixel_type(),_cimg_mp_calling_function,
15403  expr._data);
15404  }
15405  return res;
15406  }
15407 
15408  // Tell for each character of an expression if it is inside a string or not.
15409  CImg<boolT> is_inside_string(CImg<charT>& expr) const {
15410  bool is_escaped = false, next_is_escaped = false;
15411  unsigned int mode = 0, next_mode = 0; // { 0=normal | 1=char-string | 2=vector-string
15412  CImg<boolT> res = CImg<charT>::string(expr);
15413  bool *pd = res._data;
15414  for (const char *ps = expr._data; *ps; ++ps) {
15415  if (!next_is_escaped && *ps=='\\') next_is_escaped = true;
15416  if (!is_escaped && *ps=='\'') { // Non-escaped character
15417  if (!mode && ps>expr._data && *(ps - 1)=='[') next_mode = mode = 2; // Start vector-string
15418  else if (mode==2 && *(ps + 1)==']') next_mode = !mode; // End vector-string
15419  else if (mode<2) next_mode = mode?(mode = 0):1; // Start/end char-string
15420  }
15421  *(pd++) = mode>=1 || is_escaped;
15422  mode = next_mode;
15423  is_escaped = next_is_escaped;
15424  next_is_escaped = false;
15425  }
15426  return res;
15427  }
15428 
15429  // Compilation procedure.
15430  unsigned int compile(char *ss, char *se, const unsigned int depth, unsigned int *const p_ref,
15431  const bool is_single) {
15432  if (depth>256) {
15433  cimg::strellipsize(expr,64);
15434  throw CImgArgumentException("[" cimg_appname "_math_parser] "
15435  "CImg<%s>::%s: Call stack overflow (infinite recursion?), "
15436  "in expression '%s%s%s'.",
15437  pixel_type(),_cimg_mp_calling_function,
15438  (ss - 4)>expr._data?"...":"",
15439  (ss - 4)>expr._data?ss - 4:expr._data,
15440  se<&expr.back()?"...":"");
15441  }
15442  char c1, c2, c3, c4;
15443 
15444  // Simplify expression when possible.
15445  do {
15446  c2 = 0;
15447  if (ss<se) {
15448  while (*ss && ((signed char)*ss<=' ' || *ss==';')) ++ss;
15449  while (se>ss && ((signed char)(c1 = *(se - 1))<=' ' || c1==';')) --se;
15450  }
15451  while (*ss=='(' && *(se - 1)==')' && std::strchr(ss,')')==se - 1) {
15452  ++ss; --se; c2 = 1;
15453  }
15454  } while (c2 && ss<se);
15455 
15456  if (se<=ss || !*ss) {
15457  cimg::strellipsize(expr,64);
15458  throw CImgArgumentException("[" cimg_appname "_math_parser] "
15459  "CImg<%s>::%s: %s%s Missing %s, in expression '%s%s%s'.",
15460  pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",
15461  *s_op=='F'?"argument":"item",
15462  (ss_op - 4)>expr._data?"...":"",
15463  (ss_op - 4)>expr._data?ss_op - 4:expr._data,
15464  ss_op + std::strlen(ss_op)<&expr.back()?"...":"");
15465  }
15466 
15467  const char *const previous_s_op = s_op, *const previous_ss_op = ss_op;
15468  const unsigned int depth1 = depth + 1;
15469  unsigned int pos, p1, p2, p3, arg1, arg2, arg3, arg4, arg5, arg6;
15470  char
15471  *const se1 = se - 1, *const se2 = se - 2, *const se3 = se - 3,
15472  *const ss1 = ss + 1, *const ss2 = ss + 2, *const ss3 = ss + 3, *const ss4 = ss + 4,
15473  *const ss5 = ss + 5, *const ss6 = ss + 6, *const ss7 = ss + 7, *const ss8 = ss + 8,
15474  *s, *ps, *ns, *s0, *s1, *s2, *s3, sep = 0, end = 0;
15475  double val, val1, val2;
15476  mp_func op;
15477 
15478  // 'p_ref' is a 'unsigned int[7]' used to return a reference to an image or vector value
15479  // linked to the returned memory slot (reference that cannot be determined at compile time).
15480  // p_ref[0] can be { 0 = scalar (unlinked) | 1 = vector value | 2 = image value (offset) |
15481  // 3 = image value (coordinates) | 4 = image value as a vector (offsets) |
15482  // 5 = image value as a vector (coordinates) }.
15483  // Depending on p_ref[0], the remaining p_ref[k] have the following meaning:
15484  // When p_ref[0]==0, p_ref is actually unlinked.
15485  // When p_ref[0]==1, p_ref = [ 1, vector_ind, offset ].
15486  // When p_ref[0]==2, p_ref = [ 2, image_ind (or ~0U), is_relative, offset ].
15487  // When p_ref[0]==3, p_ref = [ 3, image_ind (or ~0U), is_relative, x, y, z, c ].
15488  // When p_ref[0]==4, p_ref = [ 4, image_ind (or ~0U), is_relative, offset ].
15489  // When p_ref[0]==5, p_ref = [ 5, image_ind (or ~0U), is_relative, x, y, z ].
15490  if (p_ref) { *p_ref = 0; p_ref[1] = p_ref[2] = p_ref[3] = p_ref[4] = p_ref[5] = p_ref[6] = ~0U; }
15491 
15492  const char saved_char = *se; *se = 0;
15493  const unsigned int clevel = level[ss - expr._data], clevel1 = clevel + 1;
15494  bool is_sth, is_relative;
15495  CImg<uintT> ref;
15496  CImgList<ulongT> _opcode;
15497  CImg<charT> variable_name;
15498 
15499  // Look for a single value or a pre-defined variable.
15500  int nb = cimg_sscanf(ss,"%lf%c%c",&val,&(sep=0),&(end=0));
15501 
15502 #if cimg_OS==2
15503  // Check for +/-NaN and +/-inf as Microsoft's sscanf() version is not able
15504  // to read those particular values.
15505  if (!nb && (*ss=='+' || *ss=='-' || *ss=='i' || *ss=='I' || *ss=='n' || *ss=='N')) {
15506  is_sth = true;
15507  s = ss;
15508  if (*s=='+') ++s; else if (*s=='-') { ++s; is_sth = false; }
15509  if (!cimg::strcasecmp(s,"inf")) { val = cimg::type<double>::inf(); nb = 1; }
15510  else if (!cimg::strcasecmp(s,"nan")) { val = cimg::type<double>::nan(); nb = 1; }
15511  if (nb==1 && !is_sth) val = -val;
15512  }
15513 #endif
15514  if (nb==1) _cimg_mp_constant(val);
15515  if (nb==2 && sep=='%') _cimg_mp_constant(val/100);
15516 
15517  if (ss1==se) switch (*ss) { // One-char reserved variable
15518  case 'c' : _cimg_mp_return(reserved_label['c']!=~0U?reserved_label['c']:_cimg_mp_slot_c);
15519  case 'd' : _cimg_mp_return(reserved_label['d']!=~0U?reserved_label['d']:20);
15520  case 'e' : _cimg_mp_return(reserved_label['e']!=~0U?reserved_label['e']:27);
15521  case 'h' : _cimg_mp_return(reserved_label['h']!=~0U?reserved_label['h']:19);
15522  case 'l' : _cimg_mp_return(reserved_label['l']!=~0U?reserved_label['l']:26);
15523  case 'r' : _cimg_mp_return(reserved_label['r']!=~0U?reserved_label['r']:22);
15524  case 's' : _cimg_mp_return(reserved_label['s']!=~0U?reserved_label['s']:21);
15525  case 't' : _cimg_mp_return(reserved_label['t']!=~0U?reserved_label['t']:17);
15526  case 'w' : _cimg_mp_return(reserved_label['w']!=~0U?reserved_label['w']:18);
15527  case 'x' : _cimg_mp_return(reserved_label['x']!=~0U?reserved_label['x']:_cimg_mp_slot_x);
15528  case 'y' : _cimg_mp_return(reserved_label['y']!=~0U?reserved_label['y']:_cimg_mp_slot_y);
15529  case 'z' : _cimg_mp_return(reserved_label['z']!=~0U?reserved_label['z']:_cimg_mp_slot_z);
15530  case 'u' :
15531  if (reserved_label['u']!=~0U) _cimg_mp_return(reserved_label['u']);
15532  _cimg_mp_scalar2(mp_u,0,1);
15533  case 'g' :
15534  if (reserved_label['g']!=~0U) _cimg_mp_return(reserved_label['g']);
15535  _cimg_mp_scalar0(mp_g);
15536  case 'i' :
15537  if (reserved_label['i']!=~0U) _cimg_mp_return(reserved_label['i']);
15538  _cimg_mp_scalar0(mp_i);
15539  case 'I' :
15540  _cimg_mp_op("Variable 'I'");
15541  if (reserved_label['I']!=~0U) _cimg_mp_return(reserved_label['I']);
15542  _cimg_mp_check_vector0(imgin._spectrum);
15543  need_input_copy = true;
15544  pos = vector(imgin._spectrum);
15545  CImg<ulongT>::vector((ulongT)mp_Joff,pos,0,0,imgin._spectrum).move_to(code);
15546  _cimg_mp_return(pos);
15547  case 'R' :
15548  if (reserved_label['R']!=~0U) _cimg_mp_return(reserved_label['R']);
15549  need_input_copy = true;
15550  _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,0,0,0);
15551  case 'G' :
15552  if (reserved_label['G']!=~0U) _cimg_mp_return(reserved_label['G']);
15553  need_input_copy = true;
15554  _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,1,0,0);
15555  case 'B' :
15556  if (reserved_label['B']!=~0U) _cimg_mp_return(reserved_label['B']);
15557  need_input_copy = true;
15558  _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,2,0,0);
15559  case 'A' :
15560  if (reserved_label['A']!=~0U) _cimg_mp_return(reserved_label['A']);
15561  need_input_copy = true;
15562  _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,3,0,0);
15563  }
15564  else if (ss2==se) { // Two-chars reserved variable
15565  arg1 = arg2 = ~0U;
15566  if (*ss=='w' && *ss1=='h') // wh
15567  _cimg_mp_return(reserved_label[0]!=~0U?reserved_label[0]:23);
15568  if (*ss=='p' && *ss1=='i') // pi
15569  _cimg_mp_return(reserved_label[3]!=~0U?reserved_label[3]:28);
15570  if (*ss=='i') {
15571  if (*ss1>='0' && *ss1<='9') { // i0...i9
15572  pos = 19 + *ss1 - '0';
15573  if (reserved_label[pos]!=~0U) _cimg_mp_return(reserved_label[pos]);
15574  need_input_copy = true;
15575  _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,pos - 19,0,0);
15576  }
15577  switch (*ss1) {
15578  case 'm' : arg1 = 4; arg2 = 0; break; // im
15579  case 'M' : arg1 = 5; arg2 = 1; break; // iM
15580  case 'a' : arg1 = 6; arg2 = 2; break; // ia
15581  case 'v' : arg1 = 7; arg2 = 3; break; // iv
15582  case 's' : arg1 = 8; arg2 = 12; break; // is
15583  case 'p' : arg1 = 9; arg2 = 13; break; // ip
15584  case 'c' : // ic
15585  if (reserved_label[10]!=~0U) _cimg_mp_return(reserved_label[10]);
15586  if (mem_img_median==~0U) mem_img_median = imgin?constant(imgin.median()):0;
15587  _cimg_mp_return(mem_img_median);
15588  break;
15589  }
15590  }
15591  else if (*ss1=='m') switch (*ss) {
15592  case 'x' : arg1 = 11; arg2 = 4; break; // xm
15593  case 'y' : arg1 = 12; arg2 = 5; break; // ym
15594  case 'z' : arg1 = 13; arg2 = 6; break; // zm
15595  case 'c' : arg1 = 14; arg2 = 7; break; // cm
15596  }
15597  else if (*ss1=='M') switch (*ss) {
15598  case 'x' : arg1 = 15; arg2 = 8; break; // xM
15599  case 'y' : arg1 = 16; arg2 = 9; break; // yM
15600  case 'z' : arg1 = 17; arg2 = 10; break; // zM
15601  case 'c' : arg1 = 18; arg2 = 11; break; // cM
15602  }
15603  if (arg1!=~0U) {
15604  if (reserved_label[arg1]!=~0U) _cimg_mp_return(reserved_label[arg1]);
15605  if (!img_stats) {
15606  img_stats.assign(1,14,1,1,0).fill(imgin.get_stats(),false);
15607  mem_img_stats.assign(1,14,1,1,~0U);
15608  }
15609  if (mem_img_stats[arg2]==~0U) mem_img_stats[arg2] = constant(img_stats[arg2]);
15610  _cimg_mp_return(mem_img_stats[arg2]);
15611  }
15612  } else if (ss3==se) { // Three-chars reserved variable
15613  if (*ss=='w' && *ss1=='h' && *ss2=='d') // whd
15614  _cimg_mp_return(reserved_label[1]!=~0U?reserved_label[1]:24);
15615  } else if (ss4==se) { // Four-chars reserved variable
15616  if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='s') // whds
15617  _cimg_mp_return(reserved_label[2]!=~0U?reserved_label[2]:25);
15618  }
15619 
15620  pos = ~0U;
15621  is_sth = false;
15622  for (s0 = ss, s = ss1; s<se1; ++s)
15623  if (*s==';' && level[s - expr._data]==clevel) { // Separator ';'
15624  arg1 = code_end._width;
15625  arg2 = compile(s0,s++,depth,0,is_single);
15626  if (code_end._width==arg1) pos = arg2; // makes 'end()' return void
15627  is_sth = true;
15628  while (*s && ((signed char)*s<=' ' || *s==';')) ++s;
15629  s0 = s;
15630  }
15631  if (is_sth) {
15632  arg1 = code_end._width;
15633  arg2 = compile(s0,se,depth,p_ref,is_single);
15634  if (code_end._width==arg1) pos = arg2; // makes 'end()' return void
15635  _cimg_mp_return(pos);
15636  }
15637 
15638  // Declare / assign variable, vector value or image value.
15639  for (s = ss1, ps = ss, ns = ss2; s<se1; ++s, ++ps, ++ns)
15640  if (*s=='=' && *ns!='=' && *ps!='=' && *ps!='>' && *ps!='<' && *ps!='!' &&
15641  *ps!='+' && *ps!='-' && *ps!='*' && *ps!='/' && *ps!='%' &&
15642  *ps!='>' && *ps!='<' && *ps!='&' && *ps!='|' && *ps!='^' &&
15643  level[s - expr._data]==clevel) {
15644  variable_name.assign(ss,(unsigned int)(s + 1 - ss)).back() = 0;
15645  cimg::strpare(variable_name,false,true);
15646  const unsigned int l_variable_name = (unsigned int)std::strlen(variable_name);
15647  char *const ve1 = ss + l_variable_name - 1;
15648  _cimg_mp_op("Operator '='");
15649 
15650  // Assign image value (direct).
15651  if (l_variable_name>2 && (*ss=='i' || *ss=='j' || *ss=='I' || *ss=='J') && (*ss1=='(' || *ss1=='[') &&
15652  (reserved_label[*ss]==~0U || *ss1=='(' || !_cimg_mp_is_vector(reserved_label[*ss]))) {
15653  is_relative = *ss=='j' || *ss=='J';
15654 
15655  if (*ss1=='[' && *ve1==']') { // i/j/I/J[_#ind,offset] = value
15656  if (!is_single) is_parallelizable = false;
15657  if (*ss2=='#') { // Index specified
15658  s0 = ss3; while (s0<ve1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
15659  p1 = compile(ss3,s0++,depth1,0,is_single);
15660  _cimg_mp_check_list(true);
15661  } else { p1 = ~0U; s0 = ss2; }
15662  arg1 = compile(s0,ve1,depth1,0,is_single); // Offset
15663  _cimg_mp_check_type(arg1,0,1,0);
15664  arg2 = compile(s + 1,se,depth1,0,is_single); // Value to assign
15665  if (_cimg_mp_is_vector(arg2)) {
15666  p2 = ~0U; // 'p2' must be the dimension of the vector-valued operand if any
15667  if (p1==~0U) p2 = imgin._spectrum;
15668  else if (_cimg_mp_is_constant(p1)) {
15669  p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width());
15670  p2 = listin[p3]._spectrum;
15671  }
15672  _cimg_mp_check_vector0(p2);
15673  } else p2 = 0;
15674  _cimg_mp_check_type(arg2,2,*ss>='i'?1:3,p2);
15675 
15676  if (p_ref) {
15677  *p_ref = _cimg_mp_is_vector(arg2)?4:2;
15678  p_ref[1] = p1;
15679  p_ref[2] = (unsigned int)is_relative;
15680  p_ref[3] = arg1;
15681  if (_cimg_mp_is_vector(arg2))
15682  set_variable_vector(arg2); // Prevent from being used in further optimization
15683  else if (_cimg_mp_is_comp(arg2)) memtype[arg2] = -2;
15684  if (p1!=~0U && _cimg_mp_is_comp(p1)) memtype[p1] = -2;
15685  if (_cimg_mp_is_comp(arg1)) memtype[arg1] = -2;
15686  }
15687 
15688 
15689  if (p1!=~0U) {
15690  if (!listout) _cimg_mp_return(arg2);
15691  if (*ss>='i')
15692  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_joff:mp_list_set_ioff),
15693  arg2,p1,arg1).move_to(code);
15694  else if (_cimg_mp_is_scalar(arg2))
15695  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Joff_s:mp_list_set_Ioff_s),
15696  arg2,p1,arg1).move_to(code);
15697  else
15698  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v),
15699  arg2,p1,arg1,_cimg_mp_size(arg2)).move_to(code);
15700  } else {
15701  if (!imgout) _cimg_mp_return(arg2);
15702  if (*ss>='i')
15703  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_joff:mp_set_ioff),
15704  arg2,arg1).move_to(code);
15705  else if (_cimg_mp_is_scalar(arg2))
15706  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Joff_s:mp_set_Ioff_s),
15707  arg2,arg1).move_to(code);
15708  else
15709  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v),
15710  arg2,arg1,_cimg_mp_size(arg2)).move_to(code);
15711  }
15712  _cimg_mp_return(arg2);
15713  }
15714 
15715  if (*ss1=='(' && *ve1==')') { // i/j/I/J(_#ind,_x,_y,_z,_c) = value
15716  if (!is_single) is_parallelizable = false;
15717  if (*ss2=='#') { // Index specified
15718  s0 = ss3; while (s0<ve1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
15719  p1 = compile(ss3,s0++,depth1,0,is_single);
15720  _cimg_mp_check_list(true);
15721  } else { p1 = ~0U; s0 = ss2; }
15722  arg1 = is_relative?0U:(unsigned int)_cimg_mp_slot_x;
15723  arg2 = is_relative?0U:(unsigned int)_cimg_mp_slot_y;
15724  arg3 = is_relative?0U:(unsigned int)_cimg_mp_slot_z;
15725  arg4 = is_relative?0U:(unsigned int)_cimg_mp_slot_c;
15726  arg5 = compile(s + 1,se,depth1,0,is_single); // Value to assign
15727  if (s0<ve1) { // X or [ X,_Y,_Z,_C ]
15728  s1 = s0; while (s1<ve1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
15729  arg1 = compile(s0,s1,depth1,0,is_single);
15730  if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector
15731  p2 = _cimg_mp_size(arg1); // Vector size
15732  ++arg1;
15733  if (p2>1) {
15734  arg2 = arg1 + 1;
15735  if (p2>2) {
15736  arg3 = arg2 + 1;
15737  if (p2>3) arg4 = arg3 + 1;
15738  }
15739  }
15740  } else if (s1<ve1) { // Y
15741  s2 = ++s1; while (s2<ve1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
15742  arg2 = compile(s1,s2,depth1,0,is_single);
15743  if (s2<ve1) { // Z
15744  s3 = ++s2; while (s3<ve1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
15745  arg3 = compile(s2,s3,depth1,0,is_single);
15746  if (s3<ve1) arg4 = compile(++s3,ve1,depth1,0,is_single); // C
15747  }
15748  }
15749  }
15750 
15751  if (_cimg_mp_is_vector(arg5)) {
15752  p2 = ~0U; // 'p2' must be the dimension of the vector-valued operand if any
15753  if (p1==~0U) p2 = imgin._spectrum;
15754  else if (_cimg_mp_is_constant(p1)) {
15755  p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width());
15756  p2 = listin[p3]._spectrum;
15757  }
15758  _cimg_mp_check_vector0(p2);
15759  } else p2 = 0;
15760  _cimg_mp_check_type(arg5,2,*ss>='i'?1:3,p2);
15761 
15762  if (p_ref) {
15763  *p_ref = _cimg_mp_is_vector(arg5)?5:3;
15764  p_ref[1] = p1;
15765  p_ref[2] = (unsigned int)is_relative;
15766  p_ref[3] = arg1;
15767  p_ref[4] = arg2;
15768  p_ref[5] = arg3;
15769  p_ref[6] = arg4;
15770  if (_cimg_mp_is_vector(arg5))
15771  set_variable_vector(arg5); // Prevent from being used in further optimization
15772  else if (_cimg_mp_is_comp(arg5)) memtype[arg5] = -2;
15773  if (p1!=~0U && _cimg_mp_is_comp(p1)) memtype[p1] = -2;
15774  if (_cimg_mp_is_comp(arg1)) memtype[arg1] = -2;
15775  if (_cimg_mp_is_comp(arg2)) memtype[arg2] = -2;
15776  if (_cimg_mp_is_comp(arg3)) memtype[arg3] = -2;
15777  if (_cimg_mp_is_comp(arg4)) memtype[arg4] = -2;
15778  }
15779  if (p1!=~0U) {
15780  if (!listout) _cimg_mp_return(arg5);
15781  if (*ss>='i')
15782  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc),
15783  arg5,p1,arg1,arg2,arg3,arg4).move_to(code);
15784  else if (_cimg_mp_is_scalar(arg5))
15785  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Jxyz_s:mp_list_set_Ixyz_s),
15786  arg5,p1,arg1,arg2,arg3).move_to(code);
15787  else
15788  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v),
15789  arg5,p1,arg1,arg2,arg3,_cimg_mp_size(arg5)).move_to(code);
15790  } else {
15791  if (!imgout) _cimg_mp_return(arg5);
15792  if (*ss>='i')
15793  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_jxyzc:mp_set_ixyzc),
15794  arg5,arg1,arg2,arg3,arg4).move_to(code);
15795  else if (_cimg_mp_is_scalar(arg5))
15796  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Jxyz_s:mp_set_Ixyz_s),
15797  arg5,arg1,arg2,arg3).move_to(code);
15798  else
15799  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v),
15800  arg5,arg1,arg2,arg3,_cimg_mp_size(arg5)).move_to(code);
15801  }
15802  _cimg_mp_return(arg5);
15803  }
15804  }
15805 
15806  // Assign vector value (direct).
15807  if (l_variable_name>3 && *ve1==']' && *ss!='[') {
15808  s0 = ve1; while (s0>ss && (*s0!='[' || level[s0 - expr._data]!=clevel)) --s0;
15809  is_sth = true; // is_valid_variable_name?
15810  if (*ss>='0' && *ss<='9') is_sth = false;
15811  else for (ns = ss; ns<s0; ++ns)
15812  if (!is_varchar(*ns)) { is_sth = false; break; }
15813  if (is_sth && s0>ss) {
15814  variable_name[s0 - ss] = 0; // Remove brackets in variable name
15815  arg1 = ~0U; // Vector slot
15816  arg2 = compile(++s0,ve1,depth1,0,is_single); // Index
15817  arg3 = compile(s + 1,se,depth1,0,is_single); // Value to assign
15818  _cimg_mp_check_type(arg3,2,1,0);
15819 
15820  if (variable_name[1]) { // Multi-char variable
15821  cimglist_for(variable_def,i) if (!std::strcmp(variable_name,variable_def[i])) {
15822  arg1 = variable_pos[i]; break;
15823  }
15824  } else arg1 = reserved_label[*variable_name]; // Single-char variable
15825  if (arg1==~0U) compile(ss,s0 - 1,depth1,0,is_single); // Variable does not exist -> error
15826  else { // Variable already exists
15827  if (_cimg_mp_is_scalar(arg1)) compile(ss,s,depth1,0,is_single); // Variable is not a vector -> error
15828  if (_cimg_mp_is_constant(arg2)) { // Constant index -> return corresponding variable slot directly
15829  nb = (int)mem[arg2];
15830  if (nb>=0 && nb<(int)_cimg_mp_size(arg1)) {
15831  arg1+=nb + 1;
15832  CImg<ulongT>::vector((ulongT)mp_copy,arg1,arg3).move_to(code);
15833  _cimg_mp_return(arg1);
15834  }
15835  compile(ss,s,depth1,0,is_single); // Out-of-bounds reference -> error
15836  }
15837 
15838  // Case of non-constant index -> return assigned value + linked reference
15839  if (p_ref) {
15840  *p_ref = 1;
15841  p_ref[1] = arg1;
15842  p_ref[2] = arg2;
15843  if (_cimg_mp_is_comp(arg3)) memtype[arg3] = -2; // Prevent from being used in further optimization
15844  if (_cimg_mp_is_comp(arg2)) memtype[arg2] = -2;
15845  }
15846  CImg<ulongT>::vector((ulongT)mp_vector_set_off,arg3,arg1,(ulongT)_cimg_mp_size(arg1),
15847  arg2,arg3).
15848  move_to(code);
15849  _cimg_mp_return(arg3);
15850  }
15851  }
15852  }
15853 
15854  // Assign user-defined macro.
15855  if (l_variable_name>2 && *ve1==')' && *ss!='(') {
15856  s0 = ve1; while (s0>ss && *s0!='(') --s0;
15857  is_sth = std::strncmp(variable_name,"debug(",6) &&
15858  std::strncmp(variable_name,"print(",6); // is_valid_function_name?
15859  if (*ss>='0' && *ss<='9') is_sth = false;
15860  else for (ns = ss; ns<s0; ++ns)
15861  if (!is_varchar(*ns)) { is_sth = false; break; }
15862 
15863  if (is_sth && s0>ss) { // Looks like a valid function declaration
15864  s0 = variable_name._data + (s0 - ss);
15865  *s0 = 0;
15866  s1 = variable_name._data + l_variable_name - 1; // Pointer to closing parenthesis
15867  CImg<charT>(variable_name._data,(unsigned int)(s0 - variable_name._data + 1)).move_to(macro_def,0);
15868  ++s; while (*s && (signed char)*s<=' ') ++s;
15869  CImg<charT>(s,(unsigned int)(se - s + 1)).move_to(macro_body,0);
15870 
15871  p1 = 1; // Indice of current parsed argument
15872  for (s = s0 + 1; s<=s1; ++p1, s = ns + 1) { // Parse function arguments
15873  if (p1>24) {
15874  *se = saved_char;
15875  cimg::strellipsize(variable_name,64);
15876  s0 = ss - 4>expr._data?ss - 4:expr._data;
15877  cimg::strellipsize(s0,64);
15878  throw CImgArgumentException("[" cimg_appname "_math_parser] "
15879  "CImg<%s>::%s: %s: Too much specified arguments (>24) in macro "
15880  "definition '%s()', in expression '%s%s%s'.",
15881  pixel_type(),_cimg_mp_calling_function,s_op,
15882  variable_name._data,
15883  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
15884  }
15885  while (*s && (signed char)*s<=' ') ++s;
15886  if (*s==')' && p1==1) break; // Function has no arguments
15887 
15888  s2 = s; // Start of the argument name
15889  is_sth = true; // is_valid_argument_name?
15890  if (*s>='0' && *s<='9') is_sth = false;
15891  else for (ns = s; ns<s1 && *ns!=',' && (signed char)*ns>' '; ++ns)
15892  if (!is_varchar(*ns)) { is_sth = false; break; }
15893  s3 = ns; // End of the argument name
15894  while (*ns && (signed char)*ns<=' ') ++ns;
15895  if (!is_sth || s2==s3 || (*ns!=',' && ns!=s1)) {
15896  *se = saved_char;
15897  cimg::strellipsize(variable_name,64);
15898  s0 = ss - 4>expr._data?ss - 4:expr._data;
15899  cimg::strellipsize(s0,64);
15900  throw CImgArgumentException("[" cimg_appname "_math_parser] "
15901  "CImg<%s>::%s: %s: %s name specified for argument %u when defining "
15902  "macro '%s()', in expression '%s%s%s'.",
15903  pixel_type(),_cimg_mp_calling_function,s_op,
15904  is_sth?"Empty":"Invalid",p1,
15905  variable_name._data,
15906  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
15907  }
15908  if (ns==s1 || *ns==',') { // New argument found
15909  *s3 = 0;
15910  p2 = (unsigned int)(s3 - s2); // Argument length
15911  for (ps = std::strstr(macro_body[0],s2); ps; ps = std::strstr(ps,s2)) { // Replace by arg number
15912  if (!((ps>macro_body[0]._data && is_varchar(*(ps - 1))) ||
15913  (ps + p2<macro_body[0].end() && is_varchar(*(ps + p2))))) {
15914  if (ps>macro_body[0]._data && *(ps - 1)=='#') { // Remove pre-number sign
15915  *(ps - 1) = (char)p1;
15916  if (ps + p2<macro_body[0].end() && *(ps + p2)=='#') { // Has pre & post number signs
15917  std::memmove(ps,ps + p2 + 1,macro_body[0].end() - ps - p2 - 1);
15918  macro_body[0]._width-=p2 + 1;
15919  } else { // Has pre number sign only
15920  std::memmove(ps,ps + p2,macro_body[0].end() - ps - p2);
15921  macro_body[0]._width-=p2;
15922  }
15923  } else if (ps + p2<macro_body[0].end() && *(ps + p2)=='#') { // Remove post-number sign
15924  *(ps++) = (char)p1;
15925  std::memmove(ps,ps + p2,macro_body[0].end() - ps - p2);
15926  macro_body[0]._width-=p2;
15927  } else { // Not near a number sign
15928  if (p2<3) {
15929  ps-=(ulongT)macro_body[0]._data;
15930  macro_body[0].resize(macro_body[0]._width - p2 + 3,1,1,1,0);
15931  ps+=(ulongT)macro_body[0]._data;
15932  } else macro_body[0]._width-=p2 - 3;
15933  std::memmove(ps + 3,ps + p2,macro_body[0].end() - ps - 3);
15934  *(ps++) = '(';
15935  *(ps++) = (char)p1;
15936  *(ps++) = ')';
15937  }
15938  } else ++ps;
15939  }
15940  }
15941  }
15942 
15943  // Store number of arguments.
15944  macro_def[0].resize(macro_def[0]._width + 1,1,1,1,0).back() = (char)(p1 - 1);
15945 
15946  // Detect parts of function body inside a string.
15947  is_inside_string(macro_body[0]).move_to(macro_body_is_string,0);
15948  _cimg_mp_return_nan();
15949  }
15950  }
15951 
15952  // Check if the variable name could be valid. If not, this is probably an lvalue assignment.
15953  is_sth = true; // is_valid_variable_name?
15954  const bool is_const = l_variable_name>6 && !std::strncmp(variable_name,"const ",6);
15955 
15956  s0 = variable_name._data;
15957  if (is_const) {
15958  s0+=6; while ((signed char)*s0<=' ') ++s0;
15959  variable_name.resize(variable_name.end() - s0,1,1,1,0,0,1);
15960  }
15961 
15962  if (*variable_name>='0' && *variable_name<='9') is_sth = false;
15963  else for (ns = variable_name._data; *ns; ++ns)
15964  if (!is_varchar(*ns)) { is_sth = false; break; }
15965 
15966  // Assign variable (direct).
15967  if (is_sth) {
15968  arg3 = variable_name[1]?~0U:*variable_name; // One-char variable
15969  if (variable_name[1] && !variable_name[2]) { // Two-chars variable
15970  c1 = variable_name[0];
15971  c2 = variable_name[1];
15972  if (c1=='w' && c2=='h') arg3 = 0; // wh
15973  else if (c1=='p' && c2=='i') arg3 = 3; // pi
15974  else if (c1=='i') {
15975  if (c2>='0' && c2<='9') arg3 = 19 + c2 - '0'; // i0...i9
15976  else if (c2=='m') arg3 = 4; // im
15977  else if (c2=='M') arg3 = 5; // iM
15978  else if (c2=='a') arg3 = 6; // ia
15979  else if (c2=='v') arg3 = 7; // iv
15980  else if (c2=='s') arg3 = 8; // is
15981  else if (c2=='p') arg3 = 9; // ip
15982  else if (c2=='c') arg3 = 10; // ic
15983  } else if (c2=='m') {
15984  if (c1=='x') arg3 = 11; // xm
15985  else if (c1=='y') arg3 = 12; // ym
15986  else if (c1=='z') arg3 = 13; // zm
15987  else if (c1=='c') arg3 = 14; // cm
15988  } else if (c2=='M') {
15989  if (c1=='x') arg3 = 15; // xM
15990  else if (c1=='y') arg3 = 16; // yM
15991  else if (c1=='z') arg3 = 17; // zM
15992  else if (c1=='c') arg3 = 18; // cM
15993  }
15994  } else if (variable_name[1] && variable_name[2] && !variable_name[3]) { // Three-chars variable
15995  c1 = variable_name[0];
15996  c2 = variable_name[1];
15997  c3 = variable_name[2];
15998  if (c1=='w' && c2=='h' && c3=='d') arg3 = 1; // whd
15999  } else if (variable_name[1] && variable_name[2] && variable_name[3] &&
16000  !variable_name[4]) { // Four-chars variable
16001  c1 = variable_name[0];
16002  c2 = variable_name[1];
16003  c3 = variable_name[2];
16004  c4 = variable_name[3];
16005  if (c1=='w' && c2=='h' && c3=='d' && c4=='s') arg3 = 2; // whds
16006  } else if (!std::strcmp(variable_name,"interpolation")) arg3 = 29; // interpolation
16007  else if (!std::strcmp(variable_name,"boundary")) arg3 = 30; // boundary
16008 
16009  arg1 = ~0U;
16010  arg2 = compile(s + 1,se,depth1,0,is_single);
16011  if (is_const) _cimg_mp_check_constant(arg2,2,0);
16012 
16013  if (arg3!=~0U) // One-char variable, or variable in reserved_labels
16014  arg1 = reserved_label[arg3];
16015  else // Multi-char variable name : check for existing variable with same name
16016  cimglist_for(variable_def,i)
16017  if (!std::strcmp(variable_name,variable_def[i])) { arg1 = variable_pos[i]; break; }
16018 
16019  if (arg1==~0U) { // Create new variable
16020  if (_cimg_mp_is_vector(arg2)) { // Vector variable
16021  arg1 = is_comp_vector(arg2)?arg2:vector_copy(arg2);
16022  set_variable_vector(arg1);
16023  } else { // Scalar variable
16024  if (is_const) arg1 = arg2;
16025  else {
16026  arg1 = _cimg_mp_is_comp(arg2)?arg2:scalar1(mp_copy,arg2);
16027  memtype[arg1] = -1;
16028  }
16029  }
16030 
16031  if (arg3!=~0U) reserved_label[arg3] = arg1;
16032  else {
16033  if (variable_def._width>=variable_pos._width) variable_pos.resize(-200,1,1,1,0);
16034  variable_pos[variable_def._width] = arg1;
16035  variable_name.move_to(variable_def);
16036  }
16037 
16038  } else { // Variable already exists -> assign a new value
16039  if (is_const || _cimg_mp_is_constant(arg1)) {
16040  *se = saved_char;
16041  cimg::strellipsize(variable_name,64);
16042  s0 = ss - 4>expr._data?ss - 4:expr._data;
16043  cimg::strellipsize(s0,64);
16044  throw CImgArgumentException("[" cimg_appname "_math_parser] "
16045  "CImg<%s>::%s: %s: Invalid assignment of %sconst variable '%s'%s, "
16046  "in expression '%s%s%s'.",
16047  pixel_type(),_cimg_mp_calling_function,s_op,
16048  _cimg_mp_is_constant(arg1)?"already-defined ":"non-",
16049  variable_name._data,
16050  !_cimg_mp_is_constant(arg1) && is_const?" as a new const variable":"",
16051  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
16052  }
16053  _cimg_mp_check_type(arg2,2,_cimg_mp_is_vector(arg1)?3:1,_cimg_mp_size(arg1));
16054  if (_cimg_mp_is_vector(arg1)) { // Vector
16055  if (_cimg_mp_is_vector(arg2)) // From vector
16056  CImg<ulongT>::vector((ulongT)mp_vector_copy,arg1,arg2,(ulongT)_cimg_mp_size(arg1)).
16057  move_to(code);
16058  else // From scalar
16059  CImg<ulongT>::vector((ulongT)mp_vector_init,arg1,1,(ulongT)_cimg_mp_size(arg1),arg2).
16060  move_to(code);
16061  } else // Scalar
16062  CImg<ulongT>::vector((ulongT)mp_copy,arg1,arg2).move_to(code);
16063  }
16064  _cimg_mp_return(arg1);
16065  }
16066 
16067  // Assign lvalue (variable name was not valid for a direct assignment).
16068  arg1 = ~0U;
16069  is_sth = (bool)std::strchr(variable_name,'?'); // Contains_ternary_operator?
16070  if (is_sth) break; // Do nothing and make ternary operator prioritary over assignment
16071 
16072  if (l_variable_name>2 && (std::strchr(variable_name,'(') || std::strchr(variable_name,'['))) {
16073  ref.assign(7);
16074  arg1 = compile(ss,s,depth1,ref,is_single); // Lvalue slot
16075  arg2 = compile(s + 1,se,depth1,0,is_single); // Value to assign
16076 
16077  if (*ref==1) { // Vector value (scalar): V[k] = scalar
16078  _cimg_mp_check_type(arg2,2,1,0);
16079  arg3 = ref[1]; // Vector slot
16080  arg4 = ref[2]; // Index
16081  if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
16082  CImg<ulongT>::vector((ulongT)mp_vector_set_off,arg2,arg3,(ulongT)_cimg_mp_size(arg3),arg4,arg2).
16083  move_to(code);
16084  _cimg_mp_return(arg2);
16085  }
16086 
16087  if (*ref==2) { // Image value (scalar): i/j[_#ind,off] = scalar
16088  if (!is_single) is_parallelizable = false;
16089  _cimg_mp_check_type(arg2,2,1,0);
16090  p1 = ref[1]; // Index
16091  is_relative = (bool)ref[2];
16092  arg3 = ref[3]; // Offset
16093  if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
16094  if (p1!=~0U) {
16095  if (!listout) _cimg_mp_return(arg2);
16096  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_joff:mp_list_set_ioff),
16097  arg2,p1,arg3).move_to(code);
16098  } else {
16099  if (!imgout) _cimg_mp_return(arg2);
16100  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_joff:mp_set_ioff),
16101  arg2,arg3).move_to(code);
16102  }
16103  _cimg_mp_return(arg2);
16104  }
16105 
16106  if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c) = scalar
16107  if (!is_single) is_parallelizable = false;
16108  _cimg_mp_check_type(arg2,2,1,0);
16109  p1 = ref[1]; // Index
16110  is_relative = (bool)ref[2];
16111  arg3 = ref[3]; // X
16112  arg4 = ref[4]; // Y
16113  arg5 = ref[5]; // Z
16114  arg6 = ref[6]; // C
16115  if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
16116  if (p1!=~0U) {
16117  if (!listout) _cimg_mp_return(arg2);
16118  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc),
16119  arg2,p1,arg3,arg4,arg5,arg6).move_to(code);
16120  } else {
16121  if (!imgout) _cimg_mp_return(arg2);
16122  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_jxyzc:mp_set_ixyzc),
16123  arg2,arg3,arg4,arg5,arg6).move_to(code);
16124  }
16125  _cimg_mp_return(arg2);
16126  }
16127 
16128  if (*ref==4) { // Image value (vector): I/J[_#ind,off] = value
16129  if (!is_single) is_parallelizable = false;
16130  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16131  p1 = ref[1]; // Index
16132  is_relative = (bool)ref[2];
16133  arg3 = ref[3]; // Offset
16134  if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
16135  if (p1!=~0U) {
16136  if (!listout) _cimg_mp_return(arg2);
16137  if (_cimg_mp_is_scalar(arg2))
16138  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Joff_s:mp_list_set_Ioff_s),
16139  arg2,p1,arg3).move_to(code);
16140  else
16141  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v),
16142  arg2,p1,arg3,_cimg_mp_size(arg2)).move_to(code);
16143  } else {
16144  if (!imgout) _cimg_mp_return(arg2);
16145  if (_cimg_mp_is_scalar(arg2))
16146  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Joff_s:mp_set_Ioff_s),
16147  arg2,arg3).move_to(code);
16148  else
16149  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v),
16150  arg2,arg3,_cimg_mp_size(arg2)).move_to(code);
16151  }
16152  _cimg_mp_return(arg2);
16153  }
16154 
16155  if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) = value
16156  if (!is_single) is_parallelizable = false;
16157  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16158  p1 = ref[1]; // Index
16159  is_relative = (bool)ref[2];
16160  arg3 = ref[3]; // X
16161  arg4 = ref[4]; // Y
16162  arg5 = ref[5]; // Z
16163  if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
16164  if (p1!=~0U) {
16165  if (!listout) _cimg_mp_return(arg2);
16166  if (_cimg_mp_is_scalar(arg2))
16167  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Jxyz_s:mp_list_set_Ixyz_s),
16168  arg2,p1,arg3,arg4,arg5).move_to(code);
16169  else
16170  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v),
16171  arg2,p1,arg3,arg4,arg5,_cimg_mp_size(arg2)).move_to(code);
16172  } else {
16173  if (!imgout) _cimg_mp_return(arg2);
16174  if (_cimg_mp_is_scalar(arg2))
16175  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Jxyz_s:mp_set_Ixyz_s),
16176  arg2,arg3,arg4,arg5).move_to(code);
16177  else
16178  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v),
16179  arg2,arg3,arg4,arg5,_cimg_mp_size(arg2)).move_to(code);
16180  }
16181  _cimg_mp_return(arg2);
16182  }
16183 
16184  if (_cimg_mp_is_vector(arg1)) { // Vector variable: V = value
16185  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16186  if (_cimg_mp_is_vector(arg2)) // From vector
16187  CImg<ulongT>::vector((ulongT)mp_vector_copy,arg1,arg2,(ulongT)_cimg_mp_size(arg1)).
16188  move_to(code);
16189  else // From scalar
16190  CImg<ulongT>::vector((ulongT)mp_vector_init,arg1,1,(ulongT)_cimg_mp_size(arg1),arg2).
16191  move_to(code);
16192  _cimg_mp_return(arg1);
16193  }
16194 
16195  if (_cimg_mp_is_variable(arg1)) { // Scalar variable: s = scalar
16196  _cimg_mp_check_type(arg2,2,1,0);
16197  CImg<ulongT>::vector((ulongT)mp_copy,arg1,arg2).move_to(code);
16198  _cimg_mp_return(arg1);
16199  }
16200  }
16201 
16202  // No assignment expressions match -> error
16203  *se = saved_char;
16204  cimg::strellipsize(variable_name,64);
16205  s0 = ss - 4>expr._data?ss - 4:expr._data;
16206  cimg::strellipsize(s0,64);
16207  throw CImgArgumentException("[" cimg_appname "_math_parser] "
16208  "CImg<%s>::%s: %s: Invalid %slvalue '%s', "
16209  "in expression '%s%s%s'.",
16210  pixel_type(),_cimg_mp_calling_function,s_op,
16211  arg1!=~0U && _cimg_mp_is_constant(arg1)?"const ":"",
16212  variable_name._data,
16213  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
16214  }
16215 
16216  // Apply unary/binary/ternary operators. The operator precedences should be the same as in C++.
16217  for (s = se2, ps = se3, ns = ps - 1; s>ss1; --s, --ps, --ns) // Here, ns = ps - 1
16218  if (*s=='=' && (*ps=='*' || *ps=='/' || *ps=='^') && *ns==*ps &&
16219  level[s - expr._data]==clevel) { // Self-operators for complex numbers only (**=,//=,^^=)
16220  _cimg_mp_op(*ps=='*'?"Operator '**='":*ps=='/'?"Operator '//='":"Operator '^^='");
16221 
16222  ref.assign(7);
16223  arg1 = compile(ss,ns,depth1,ref,is_single); // Vector slot
16224  arg2 = compile(s + 1,se,depth1,0,is_single); // Right operand
16225  _cimg_mp_check_type(arg1,1,2,2);
16226  _cimg_mp_check_type(arg2,2,3,2);
16227  if (_cimg_mp_is_vector(arg2)) { // Complex **= complex
16228  if (*ps=='*')
16229  CImg<ulongT>::vector((ulongT)mp_complex_mul,arg1,arg1,arg2).move_to(code);
16230  else if (*ps=='/')
16231  CImg<ulongT>::vector((ulongT)mp_complex_div_vv,arg1,arg1,arg2).move_to(code);
16232  else
16233  CImg<ulongT>::vector((ulongT)mp_complex_pow_vv,arg1,arg1,arg2).move_to(code);
16234  } else { // Complex **= scalar
16235  if (*ps=='*') {
16236  if (arg2==1) _cimg_mp_return(arg1);
16237  self_vector_s(arg1,mp_self_mul,arg2);
16238  } else if (*ps=='/') {
16239  if (arg2==1) _cimg_mp_return(arg1);
16240  self_vector_s(arg1,mp_self_div,arg2);
16241  } else {
16242  if (arg2==1) _cimg_mp_return(arg1);
16243  CImg<ulongT>::vector((ulongT)mp_complex_pow_vs,arg1,arg1,arg2).move_to(code);
16244  }
16245  }
16246 
16247  // Write computed value back in image if necessary.
16248  if (*ref==4) { // Image value (vector): I/J[_#ind,off] **= value
16249  if (!is_single) is_parallelizable = false;
16250  p1 = ref[1]; // Index
16251  is_relative = (bool)ref[2];
16252  arg3 = ref[3]; // Offset
16253  if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
16254  if (p1!=~0U) {
16255  if (!listout) _cimg_mp_return(arg1);
16256  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v),
16257  arg1,p1,arg3,_cimg_mp_size(arg1)).move_to(code);
16258  } else {
16259  if (!imgout) _cimg_mp_return(arg1);
16260  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v),
16261  arg1,arg3,_cimg_mp_size(arg1)).move_to(code);
16262  }
16263 
16264  } else if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) **= value
16265  if (!is_single) is_parallelizable = false;
16266  p1 = ref[1]; // Index
16267  is_relative = (bool)ref[2];
16268  arg3 = ref[3]; // X
16269  arg4 = ref[4]; // Y
16270  arg5 = ref[5]; // Z
16271  if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
16272  if (p1!=~0U) {
16273  if (!listout) _cimg_mp_return(arg1);
16274  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v),
16275  arg1,p1,arg3,arg4,arg5,_cimg_mp_size(arg1)).move_to(code);
16276  } else {
16277  if (!imgout) _cimg_mp_return(arg1);
16278  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v),
16279  arg1,arg3,arg4,arg5,_cimg_mp_size(arg1)).move_to(code);
16280  }
16281  }
16282 
16283  _cimg_mp_return(arg1);
16284  }
16285 
16286  for (s = se2, ps = se3, ns = ps - 1; s>ss1; --s, --ps, --ns) // Here, ns = ps - 1
16287  if (*s=='=' && (*ps=='+' || *ps=='-' || *ps=='*' || *ps=='/' || *ps=='%' ||
16288  *ps=='&' || *ps=='^' || *ps=='|' ||
16289  (*ps=='>' && *ns=='>') || (*ps=='<' && *ns=='<')) &&
16290  level[s - expr._data]==clevel) { // Self-operators (+=,-=,*=,/=,%=,>>=,<<=,&=,^=,|=)
16291  switch (*ps) {
16292  case '+' : op = mp_self_add; _cimg_mp_op("Operator '+='"); break;
16293  case '-' : op = mp_self_sub; _cimg_mp_op("Operator '-='"); break;
16294  case '*' : op = mp_self_mul; _cimg_mp_op("Operator '*='"); break;
16295  case '/' : op = mp_self_div; _cimg_mp_op("Operator '/='"); break;
16296  case '%' : op = mp_self_modulo; _cimg_mp_op("Operator '%='"); break;
16297  case '<' : op = mp_self_bitwise_left_shift; _cimg_mp_op("Operator '<<='"); break;
16298  case '>' : op = mp_self_bitwise_right_shift; _cimg_mp_op("Operator '>>='"); break;
16299  case '&' : op = mp_self_bitwise_and; _cimg_mp_op("Operator '&='"); break;
16300  case '|' : op = mp_self_bitwise_or; _cimg_mp_op("Operator '|='"); break;
16301  default : op = mp_self_pow; _cimg_mp_op("Operator '^='"); break;
16302  }
16303  s1 = *ps=='>' || *ps=='<'?ns:ps;
16304 
16305  ref.assign(7);
16306  arg1 = compile(ss,s1,depth1,ref,is_single); // Variable slot
16307  arg2 = compile(s + 1,se,depth1,0,is_single); // Value to apply
16308 
16309  // Check for particular case to be simplified.
16310  if ((op==mp_self_add || op==mp_self_sub) && !arg2) _cimg_mp_return(arg1);
16311  if ((op==mp_self_mul || op==mp_self_div) && arg2==1) _cimg_mp_return(arg1);
16312 
16313  // Apply operator on a copy to prevent modifying a constant or a variable.
16314  if (*ref && (_cimg_mp_is_constant(arg1) || _cimg_mp_is_vector(arg1) || _cimg_mp_is_variable(arg1))) {
16315  if (_cimg_mp_is_vector(arg1)) arg1 = vector_copy(arg1);
16316  else arg1 = scalar1(mp_copy,arg1);
16317  }
16318 
16319  if (*ref==1) { // Vector value (scalar): V[k] += scalar
16320  _cimg_mp_check_type(arg2,2,1,0);
16321  arg3 = ref[1]; // Vector slot
16322  arg4 = ref[2]; // Index
16323  if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
16324  CImg<ulongT>::vector((ulongT)op,arg1,arg2).move_to(code);
16325  CImg<ulongT>::vector((ulongT)mp_vector_set_off,arg1,arg3,(ulongT)_cimg_mp_size(arg3),arg4,arg1).
16326  move_to(code);
16327  _cimg_mp_return(arg1);
16328  }
16329 
16330  if (*ref==2) { // Image value (scalar): i/j[_#ind,off] += scalar
16331  if (!is_single) is_parallelizable = false;
16332  _cimg_mp_check_type(arg2,2,1,0);
16333  p1 = ref[1]; // Index
16334  is_relative = (bool)ref[2];
16335  arg3 = ref[3]; // Offset
16336  if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
16337  CImg<ulongT>::vector((ulongT)op,arg1,arg2).move_to(code);
16338  if (p1!=~0U) {
16339  if (!listout) _cimg_mp_return(arg1);
16340  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_joff:mp_list_set_ioff),
16341  arg1,p1,arg3).move_to(code);
16342  } else {
16343  if (!imgout) _cimg_mp_return(arg1);
16344  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_joff:mp_set_ioff),
16345  arg1,arg3).move_to(code);
16346  }
16347  _cimg_mp_return(arg1);
16348  }
16349 
16350  if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c) += scalar
16351  if (!is_single) is_parallelizable = false;
16352  _cimg_mp_check_type(arg2,2,1,0);
16353  p1 = ref[1]; // Index
16354  is_relative = (bool)ref[2];
16355  arg3 = ref[3]; // X
16356  arg4 = ref[4]; // Y
16357  arg5 = ref[5]; // Z
16358  arg6 = ref[6]; // C
16359  if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
16360  CImg<ulongT>::vector((ulongT)op,arg1,arg2).move_to(code);
16361  if (p1!=~0U) {
16362  if (!listout) _cimg_mp_return(arg1);
16363  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc),
16364  arg1,p1,arg3,arg4,arg5,arg6).move_to(code);
16365  } else {
16366  if (!imgout) _cimg_mp_return(arg1);
16367  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_jxyzc:mp_set_ixyzc),
16368  arg1,arg3,arg4,arg5,arg6).move_to(code);
16369  }
16370  _cimg_mp_return(arg1);
16371  }
16372 
16373  if (*ref==4) { // Image value (vector): I/J[_#ind,off] += value
16374  if (!is_single) is_parallelizable = false;
16375  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16376  p1 = ref[1]; // Index
16377  is_relative = (bool)ref[2];
16378  arg3 = ref[3]; // Offset
16379  if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
16380  if (_cimg_mp_is_scalar(arg2)) self_vector_s(arg1,op,arg2); else self_vector_v(arg1,op,arg2);
16381  if (p1!=~0U) {
16382  if (!listout) _cimg_mp_return(arg1);
16383  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v),
16384  arg1,p1,arg3,_cimg_mp_size(arg1)).move_to(code);
16385  } else {
16386  if (!imgout) _cimg_mp_return(arg1);
16387  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v),
16388  arg1,arg3,_cimg_mp_size(arg1)).move_to(code);
16389  }
16390  _cimg_mp_return(arg1);
16391  }
16392 
16393  if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) += value
16394  if (!is_single) is_parallelizable = false;
16395  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16396  p1 = ref[1]; // Index
16397  is_relative = (bool)ref[2];
16398  arg3 = ref[3]; // X
16399  arg4 = ref[4]; // Y
16400  arg5 = ref[5]; // Z
16401  if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
16402  if (_cimg_mp_is_scalar(arg2)) self_vector_s(arg1,op,arg2); else self_vector_v(arg1,op,arg2);
16403  if (p1!=~0U) {
16404  if (!listout) _cimg_mp_return(arg1);
16405  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v),
16406  arg1,p1,arg3,arg4,arg5,_cimg_mp_size(arg1)).move_to(code);
16407  } else {
16408  if (!imgout) _cimg_mp_return(arg1);
16409  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v),
16410  arg1,arg3,arg4,arg5,_cimg_mp_size(arg1)).move_to(code);
16411  }
16412  _cimg_mp_return(arg1);
16413  }
16414 
16415  if (_cimg_mp_is_vector(arg1)) { // Vector variable: V += value
16416  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16417  if (_cimg_mp_is_vector(arg2)) self_vector_v(arg1,op,arg2); // Vector += vector
16418  else self_vector_s(arg1,op,arg2); // Vector += scalar
16419  _cimg_mp_return(arg1);
16420  }
16421 
16422  if (_cimg_mp_is_variable(arg1)) { // Scalar variable: s += scalar
16423  _cimg_mp_check_type(arg2,2,1,0);
16424  CImg<ulongT>::vector((ulongT)op,arg1,arg2).move_to(code);
16425  _cimg_mp_return(arg1);
16426  }
16427 
16428  variable_name.assign(ss,(unsigned int)(s - ss)).back() = 0;
16429  cimg::strpare(variable_name,false,true);
16430  *se = saved_char;
16431  s0 = ss - 4>expr._data?ss - 4:expr._data;
16432  cimg::strellipsize(s0,64);
16433  throw CImgArgumentException("[" cimg_appname "_math_parser] "
16434  "CImg<%s>::%s: %s: Invalid %slvalue '%s', "
16435  "in expression '%s%s%s'.",
16436  pixel_type(),_cimg_mp_calling_function,s_op,
16437  _cimg_mp_is_constant(arg1)?"const ":"",
16438  variable_name._data,
16439  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
16440  }
16441 
16442  for (s = ss1; s<se1; ++s)
16443  if (*s=='?' && level[s - expr._data]==clevel) { // Ternary operator 'cond?expr1:expr2'
16444  _cimg_mp_op("Operator '?:'");
16445  s1 = s + 1; while (s1<se1 && (*s1!=':' || level[s1 - expr._data]!=clevel)) ++s1;
16446  arg1 = compile(ss,s,depth1,0,is_single);
16447  _cimg_mp_check_type(arg1,1,1,0);
16448  if (_cimg_mp_is_constant(arg1)) {
16449  if ((bool)mem[arg1]) return compile(s + 1,*s1!=':'?se:s1,depth1,0,is_single);
16450  else return *s1!=':'?0:compile(++s1,se,depth1,0,is_single);
16451  }
16452  p2 = code._width;
16453  arg2 = compile(s + 1,*s1!=':'?se:s1,depth1,0,is_single);
16454  p3 = code._width;
16455  arg3 = *s1==':'?compile(++s1,se,depth1,0,is_single):
16456  _cimg_mp_is_vector(arg2)?vector(_cimg_mp_size(arg2),0):0;
16457  _cimg_mp_check_type(arg3,3,_cimg_mp_is_vector(arg2)?2:1,_cimg_mp_size(arg2));
16458  arg4 = _cimg_mp_size(arg2);
16459  if (arg4) pos = vector(arg4); else pos = scalar();
16460  CImg<ulongT>::vector((ulongT)mp_if,pos,arg1,arg2,arg3,
16461  p3 - p2,code._width - p3,arg4).move_to(code,p2);
16462  _cimg_mp_return(pos);
16463  }
16464 
16465  for (s = se3, ns = se2; s>ss; --s, --ns)
16466  if (*s=='|' && *ns=='|' && level[s - expr._data]==clevel) { // Logical or ('||')
16467  _cimg_mp_op("Operator '||'");
16468  arg1 = compile(ss,s,depth1,0,is_single);
16469  _cimg_mp_check_type(arg1,1,1,0);
16470  if (arg1>0 && arg1<=16) _cimg_mp_return(1);
16471  p2 = code._width;
16472  arg2 = compile(s + 2,se,depth1,0,is_single);
16473  _cimg_mp_check_type(arg2,2,1,0);
16474  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
16475  _cimg_mp_constant(mem[arg1] || mem[arg2]);
16476  if (!arg1) _cimg_mp_return(arg2);
16477  pos = scalar();
16478  CImg<ulongT>::vector((ulongT)mp_logical_or,pos,arg1,arg2,code._width - p2).
16479  move_to(code,p2);
16480  _cimg_mp_return(pos);
16481  }
16482 
16483  for (s = se3, ns = se2; s>ss; --s, --ns)
16484  if (*s=='&' && *ns=='&' && level[s - expr._data]==clevel) { // Logical and ('&&')
16485  _cimg_mp_op("Operator '&&'");
16486  arg1 = compile(ss,s,depth1,0,is_single);
16487  _cimg_mp_check_type(arg1,1,1,0);
16488  if (!arg1) _cimg_mp_return(0);
16489  p2 = code._width;
16490  arg2 = compile(s + 2,se,depth1,0,is_single);
16491  _cimg_mp_check_type(arg2,2,1,0);
16492  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
16493  _cimg_mp_constant(mem[arg1] && mem[arg2]);
16494  if (arg1>0 && arg1<=16) _cimg_mp_return(arg2);
16495  pos = scalar();
16496  CImg<ulongT>::vector((ulongT)mp_logical_and,pos,arg1,arg2,code._width - p2).
16497  move_to(code,p2);
16498  _cimg_mp_return(pos);
16499  }
16500 
16501  for (s = se2; s>ss; --s)
16502  if (*s=='|' && level[s - expr._data]==clevel) { // Bitwise or ('|')
16503  _cimg_mp_op("Operator '|'");
16504  arg1 = compile(ss,s,depth1,0,is_single);
16505  arg2 = compile(s + 1,se,depth1,0,is_single);
16506  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16507  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_bitwise_or,arg1,arg2);
16508  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) {
16509  if (!arg2) _cimg_mp_return(arg1);
16510  _cimg_mp_vector2_vs(mp_bitwise_or,arg1,arg2);
16511  }
16512  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) {
16513  if (!arg1) _cimg_mp_return(arg2);
16514  _cimg_mp_vector2_sv(mp_bitwise_or,arg1,arg2);
16515  }
16516  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
16517  _cimg_mp_constant((longT)mem[arg1] | (longT)mem[arg2]);
16518  if (!arg2) _cimg_mp_return(arg1);
16519  if (!arg1) _cimg_mp_return(arg2);
16520  _cimg_mp_scalar2(mp_bitwise_or,arg1,arg2);
16521  }
16522 
16523  for (s = se2; s>ss; --s)
16524  if (*s=='&' && level[s - expr._data]==clevel) { // Bitwise and ('&')
16525  _cimg_mp_op("Operator '&'");
16526  arg1 = compile(ss,s,depth1,0,is_single);
16527  arg2 = compile(s + 1,se,depth1,0,is_single);
16528  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16529  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_bitwise_and,arg1,arg2);
16530  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_bitwise_and,arg1,arg2);
16531  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_bitwise_and,arg1,arg2);
16532  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
16533  _cimg_mp_constant((longT)mem[arg1] & (longT)mem[arg2]);
16534  if (!arg1 || !arg2) _cimg_mp_return(0);
16535  _cimg_mp_scalar2(mp_bitwise_and,arg1,arg2);
16536  }
16537 
16538  for (s = se3, ns = se2; s>ss; --s, --ns)
16539  if (*s=='!' && *ns=='=' && level[s - expr._data]==clevel) { // Not equal to ('!=')
16540  _cimg_mp_op("Operator '!='");
16541  arg1 = compile(ss,s,depth1,0,is_single);
16542  arg2 = compile(s + 2,se,depth1,0,is_single);
16543  if (arg1==arg2) _cimg_mp_return(0);
16544  p1 = _cimg_mp_size(arg1);
16545  p2 = _cimg_mp_size(arg2);
16546  if (p1 || p2) {
16547  if (p1 && p2 && p1!=p2) _cimg_mp_return(1);
16548  _cimg_mp_scalar6(mp_vector_neq,arg1,p1,arg2,p2,11,1);
16549  }
16550  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]!=mem[arg2]);
16551  _cimg_mp_scalar2(mp_neq,arg1,arg2);
16552  }
16553 
16554  for (s = se3, ns = se2; s>ss; --s, --ns)
16555  if (*s=='=' && *ns=='=' && level[s - expr._data]==clevel) { // Equal to ('==')
16556  _cimg_mp_op("Operator '=='");
16557  arg1 = compile(ss,s,depth1,0,is_single);
16558  arg2 = compile(s + 2,se,depth1,0,is_single);
16559  if (arg1==arg2) _cimg_mp_return(1);
16560  p1 = _cimg_mp_size(arg1);
16561  p2 = _cimg_mp_size(arg2);
16562  if (p1 || p2) {
16563  if (p1 && p2 && p1!=p2) _cimg_mp_return(0);
16564  _cimg_mp_scalar6(mp_vector_eq,arg1,p1,arg2,p2,11,1);
16565  }
16566  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]==mem[arg2]);
16567  _cimg_mp_scalar2(mp_eq,arg1,arg2);
16568  }
16569 
16570  for (s = se3, ns = se2; s>ss; --s, --ns)
16571  if (*s=='<' && *ns=='=' && level[s - expr._data]==clevel) { // Less or equal than ('<=')
16572  _cimg_mp_op("Operator '<='");
16573  arg1 = compile(ss,s,depth1,0,is_single);
16574  arg2 = compile(s + 2,se,depth1,0,is_single);
16575  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16576  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_lte,arg1,arg2);
16577  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_lte,arg1,arg2);
16578  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_lte,arg1,arg2);
16579  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]<=mem[arg2]);
16580  if (arg1==arg2) _cimg_mp_return(1);
16581  _cimg_mp_scalar2(mp_lte,arg1,arg2);
16582  }
16583 
16584  for (s = se3, ns = se2; s>ss; --s, --ns)
16585  if (*s=='>' && *ns=='=' && level[s - expr._data]==clevel) { // Greater or equal than ('>=')
16586  _cimg_mp_op("Operator '>='");
16587  arg1 = compile(ss,s,depth1,0,is_single);
16588  arg2 = compile(s + 2,se,depth1,0,is_single);
16589  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16590  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_gte,arg1,arg2);
16591  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_gte,arg1,arg2);
16592  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_gte,arg1,arg2);
16593  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]>=mem[arg2]);
16594  if (arg1==arg2) _cimg_mp_return(1);
16595  _cimg_mp_scalar2(mp_gte,arg1,arg2);
16596  }
16597 
16598  for (s = se2, ns = se1, ps = se3; s>ss; --s, --ns, --ps)
16599  if (*s=='<' && *ns!='<' && *ps!='<' && level[s - expr._data]==clevel) { // Less than ('<')
16600  _cimg_mp_op("Operator '<'");
16601  arg1 = compile(ss,s,depth1,0,is_single);
16602  arg2 = compile(s + 1,se,depth1,0,is_single);
16603  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16604  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_lt,arg1,arg2);
16605  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_lt,arg1,arg2);
16606  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_lt,arg1,arg2);
16607  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]<mem[arg2]);
16608  if (arg1==arg2) _cimg_mp_return(0);
16609  _cimg_mp_scalar2(mp_lt,arg1,arg2);
16610  }
16611 
16612  for (s = se2, ns = se1, ps = se3; s>ss; --s, --ns, --ps)
16613  if (*s=='>' && *ns!='>' && *ps!='>' && level[s - expr._data]==clevel) { // Greather than ('>')
16614  _cimg_mp_op("Operator '>'");
16615  arg1 = compile(ss,s,depth1,0,is_single);
16616  arg2 = compile(s + 1,se,depth1,0,is_single);
16617  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16618  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_gt,arg1,arg2);
16619  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_gt,arg1,arg2);
16620  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_gt,arg1,arg2);
16621  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]>mem[arg2]);
16622  if (arg1==arg2) _cimg_mp_return(0);
16623  _cimg_mp_scalar2(mp_gt,arg1,arg2);
16624  }
16625 
16626  for (s = se3, ns = se2; s>ss; --s, --ns)
16627  if (*s=='<' && *ns=='<' && level[s - expr._data]==clevel) { // Left bit shift ('<<')
16628  _cimg_mp_op("Operator '<<'");
16629  arg1 = compile(ss,s,depth1,0,is_single);
16630  arg2 = compile(s + 2,se,depth1,0,is_single);
16631  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16632  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2))
16633  _cimg_mp_vector2_vv(mp_bitwise_left_shift,arg1,arg2);
16634  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) {
16635  if (!arg2) _cimg_mp_return(arg1);
16636  _cimg_mp_vector2_vs(mp_bitwise_left_shift,arg1,arg2);
16637  }
16638  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2))
16639  _cimg_mp_vector2_sv(mp_bitwise_left_shift,arg1,arg2);
16640  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
16641  _cimg_mp_constant((longT)mem[arg1]<<(unsigned int)mem[arg2]);
16642  if (!arg1) _cimg_mp_return(0);
16643  if (!arg2) _cimg_mp_return(arg1);
16644  _cimg_mp_scalar2(mp_bitwise_left_shift,arg1,arg2);
16645  }
16646 
16647  for (s = se3, ns = se2; s>ss; --s, --ns)
16648  if (*s=='>' && *ns=='>' && level[s - expr._data]==clevel) { // Right bit shift ('>>')
16649  _cimg_mp_op("Operator '>>'");
16650  arg1 = compile(ss,s,depth1,0,is_single);
16651  arg2 = compile(s + 2,se,depth1,0,is_single);
16652  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16653  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2))
16654  _cimg_mp_vector2_vv(mp_bitwise_right_shift,arg1,arg2);
16655  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) {
16656  if (!arg2) _cimg_mp_return(arg1);
16657  _cimg_mp_vector2_vs(mp_bitwise_right_shift,arg1,arg2);
16658  }
16659  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2))
16660  _cimg_mp_vector2_sv(mp_bitwise_right_shift,arg1,arg2);
16661  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
16662  _cimg_mp_constant((longT)mem[arg1]>>(unsigned int)mem[arg2]);
16663  if (!arg1) _cimg_mp_return(0);
16664  if (!arg2) _cimg_mp_return(arg1);
16665  _cimg_mp_scalar2(mp_bitwise_right_shift,arg1,arg2);
16666  }
16667 
16668  for (ns = se1, s = se2, ps = pexpr._data + (se3 - expr._data); s>ss; --ns, --s, --ps)
16669  if (*s=='+' && (*ns!='+' || ns!=se1) && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' &&
16670  *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' && *ps!='#' &&
16671  (*ps!='e' || !(ps - pexpr._data>ss - expr._data && (*(ps - 1)=='.' || (*(ps - 1)>='0' &&
16672  *(ps - 1)<='9')))) &&
16673  level[s - expr._data]==clevel) { // Addition ('+')
16674  _cimg_mp_op("Operator '+'");
16675  arg1 = compile(ss,s,depth1,0,is_single);
16676  arg2 = compile(s + 1,se,depth1,0,is_single);
16677  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16678  if (!arg2) _cimg_mp_return(arg1);
16679  if (!arg1) _cimg_mp_return(arg2);
16680  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_add,arg1,arg2);
16681  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_add,arg1,arg2);
16682  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_add,arg1,arg2);
16683  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1] + mem[arg2]);
16684  if (code) { // Try to spot linear case 'a*b + c'.
16685  CImg<ulongT> &pop = code.back();
16686  if (pop[0]==(ulongT)mp_mul && _cimg_mp_is_comp(pop[1]) && (pop[1]==arg1 || pop[1]==arg2)) {
16687  arg3 = (unsigned int)pop[1];
16688  arg4 = (unsigned int)pop[2];
16689  arg5 = (unsigned int)pop[3];
16690  code.remove();
16691  CImg<ulongT>::vector((ulongT)mp_linear_add,arg3,arg4,arg5,arg3==arg2?arg1:arg2).move_to(code);
16692  _cimg_mp_return(arg3);
16693  }
16694  }
16695  if (arg2==1) _cimg_mp_scalar1(mp_increment,arg1);
16696  if (arg1==1) _cimg_mp_scalar1(mp_increment,arg2);
16697  _cimg_mp_scalar2(mp_add,arg1,arg2);
16698  }
16699 
16700  for (ns = se1, s = se2, ps = pexpr._data + (se3 - expr._data); s>ss; --ns, --s, --ps)
16701  if (*s=='-' && (*ns!='-' || ns!=se1) && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' &&
16702  *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' && *ps!='#' &&
16703  (*ps!='e' || !(ps - pexpr._data>ss - expr._data && (*(ps - 1)=='.' || (*(ps - 1)>='0' &&
16704  *(ps - 1)<='9')))) &&
16705  level[s - expr._data]==clevel) { // Subtraction ('-')
16706  _cimg_mp_op("Operator '-'");
16707  arg1 = compile(ss,s,depth1,0,is_single);
16708  arg2 = compile(s + 1,se,depth1,0,is_single);
16709  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16710  if (!arg2) _cimg_mp_return(arg1);
16711  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_sub,arg1,arg2);
16712  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_sub,arg1,arg2);
16713  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) {
16714  if (!arg1) _cimg_mp_vector1_v(mp_minus,arg2);
16715  _cimg_mp_vector2_sv(mp_sub,arg1,arg2);
16716  }
16717  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1] - mem[arg2]);
16718  if (!arg1) _cimg_mp_scalar1(mp_minus,arg2);
16719  if (code) { // Try to spot linear cases 'a*b - c' and 'c - a*b'.
16720  CImg<ulongT> &pop = code.back();
16721  if (pop[0]==(ulongT)mp_mul && _cimg_mp_is_comp(pop[1]) && (pop[1]==arg1 || pop[1]==arg2)) {
16722  arg3 = (unsigned int)pop[1];
16723  arg4 = (unsigned int)pop[2];
16724  arg5 = (unsigned int)pop[3];
16725  code.remove();
16726  CImg<ulongT>::vector((ulongT)(arg3==arg1?mp_linear_sub_left:mp_linear_sub_right),
16727  arg3,arg4,arg5,arg3==arg1?arg2:arg1).move_to(code);
16728  _cimg_mp_return(arg3);
16729  }
16730  }
16731  if (arg2==1) _cimg_mp_scalar1(mp_decrement,arg1);
16732  _cimg_mp_scalar2(mp_sub,arg1,arg2);
16733  }
16734 
16735  for (s = se3, ns = se2; s>ss; --s, --ns)
16736  if (*s=='*' && *ns=='*' && level[s - expr._data]==clevel) { // Complex multiplication ('**')
16737  _cimg_mp_op("Operator '**'");
16738  arg1 = compile(ss,s,depth1,0,is_single);
16739  arg2 = compile(s + 2,se,depth1,0,is_single);
16740  _cimg_mp_check_type(arg1,1,3,2);
16741  _cimg_mp_check_type(arg2,2,3,2);
16742  if (arg2==1) _cimg_mp_return(arg1);
16743  if (arg1==1) _cimg_mp_return(arg2);
16744  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) {
16745  pos = vector(2);
16746  CImg<ulongT>::vector((ulongT)mp_complex_mul,pos,arg1,arg2).move_to(code);
16747  _cimg_mp_return(pos);
16748  }
16749  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_mul,arg1,arg2);
16750  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_mul,arg1,arg2);
16751  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]*mem[arg2]);
16752  if (!arg1 || !arg2) _cimg_mp_return(0);
16753  _cimg_mp_scalar2(mp_mul,arg1,arg2);
16754  }
16755 
16756  for (s = se3, ns = se2; s>ss; --s, --ns)
16757  if (*s=='/' && *ns=='/' && level[s - expr._data]==clevel) { // Complex division ('//')
16758  _cimg_mp_op("Operator '//'");
16759  arg1 = compile(ss,s,depth1,0,is_single);
16760  arg2 = compile(s + 2,se,depth1,0,is_single);
16761  _cimg_mp_check_type(arg1,1,3,2);
16762  _cimg_mp_check_type(arg2,2,3,2);
16763  if (arg2==1) _cimg_mp_return(arg1);
16764  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) {
16765  pos = vector(2);
16766  CImg<ulongT>::vector((ulongT)mp_complex_div_vv,pos,arg1,arg2).move_to(code);
16767  _cimg_mp_return(pos);
16768  }
16769  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_div,arg1,arg2);
16770  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) {
16771  pos = vector(2);
16772  CImg<ulongT>::vector((ulongT)mp_complex_div_sv,pos,arg1,arg2).move_to(code);
16773  _cimg_mp_return(pos);
16774  }
16775  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]/mem[arg2]);
16776  if (!arg1) _cimg_mp_return(0);
16777  _cimg_mp_scalar2(mp_div,arg1,arg2);
16778  }
16779 
16780  for (s = se2; s>ss; --s) if (*s=='*' && level[s - expr._data]==clevel) { // Multiplication ('*')
16781  _cimg_mp_op("Operator '*'");
16782  arg1 = compile(ss,s,depth1,0,is_single);
16783  arg2 = compile(s + 1,se,depth1,0,is_single);
16784  p2 = _cimg_mp_size(arg2);
16785  if (p2>0 && _cimg_mp_size(arg1)==p2*p2) { // Particular case of matrix multiplication
16786  pos = vector(p2);
16787  CImg<ulongT>::vector((ulongT)mp_matrix_mul,pos,arg1,arg2,p2,p2,1).move_to(code);
16788  _cimg_mp_return(pos);
16789  }
16790  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16791  if (arg2==1) _cimg_mp_return(arg1);
16792  if (arg1==1) _cimg_mp_return(arg2);
16793  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_mul,arg1,arg2);
16794  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_mul,arg1,arg2);
16795  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_mul,arg1,arg2);
16796  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]*mem[arg2]);
16797 
16798  if (code) { // Try to spot double multiplication 'a*b*c'.
16799  CImg<ulongT> &pop = code.back();
16800  if (pop[0]==(ulongT)mp_mul && _cimg_mp_is_comp(pop[1]) && (pop[1]==arg1 || pop[1]==arg2)) {
16801  arg3 = (unsigned int)pop[1];
16802  arg4 = (unsigned int)pop[2];
16803  arg5 = (unsigned int)pop[3];
16804  code.remove();
16805  CImg<ulongT>::vector((ulongT)mp_mul2,arg3,arg4,arg5,arg3==arg2?arg1:arg2).move_to(code);
16806  _cimg_mp_return(arg3);
16807  }
16808  }
16809  if (!arg1 || !arg2) _cimg_mp_return(0);
16810  _cimg_mp_scalar2(mp_mul,arg1,arg2);
16811  }
16812 
16813  for (s = se2; s>ss; --s) if (*s=='/' && level[s - expr._data]==clevel) { // Division ('/')
16814  _cimg_mp_op("Operator '/'");
16815  arg1 = compile(ss,s,depth1,0,is_single);
16816  arg2 = compile(s + 1,se,depth1,0,is_single);
16817  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16818  if (arg2==1) _cimg_mp_return(arg1);
16819  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_div,arg1,arg2);
16820  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_div,arg1,arg2);
16821  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_div,arg1,arg2);
16822  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]/mem[arg2]);
16823  if (!arg1) _cimg_mp_return(0);
16824  _cimg_mp_scalar2(mp_div,arg1,arg2);
16825  }
16826 
16827  for (s = se2, ns = se1; s>ss; --s, --ns)
16828  if (*s=='%' && *ns!='^' && level[s - expr._data]==clevel) { // Modulo ('%')
16829  _cimg_mp_op("Operator '%'");
16830  arg1 = compile(ss,s,depth1,0,is_single);
16831  arg2 = compile(s + 1,se,depth1,0,is_single);
16832  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16833  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_modulo,arg1,arg2);
16834  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_modulo,arg1,arg2);
16835  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_modulo,arg1,arg2);
16836  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
16837  _cimg_mp_constant(cimg::mod(mem[arg1],mem[arg2]));
16838  _cimg_mp_scalar2(mp_modulo,arg1,arg2);
16839  }
16840 
16841  if (se1>ss) {
16842  if (*ss=='+' && (*ss1!='+' || (ss2<se && *ss2>='0' && *ss2<='9'))) { // Unary plus ('+')
16843  _cimg_mp_op("Operator '+'");
16844  _cimg_mp_return(compile(ss1,se,depth1,0,is_single));
16845  }
16846 
16847  if (*ss=='-' && (*ss1!='-' || (ss2<se && *ss2>='0' && *ss2<='9'))) { // Unary minus ('-')
16848  _cimg_mp_op("Operator '-'");
16849  arg1 = compile(ss1,se,depth1,0,is_single);
16850  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_minus,arg1);
16851  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(-mem[arg1]);
16852  _cimg_mp_scalar1(mp_minus,arg1);
16853  }
16854 
16855  if (*ss=='!') { // Logical not ('!')
16856  _cimg_mp_op("Operator '!'");
16857  if (*ss1=='!') { // '!!expr' optimized as 'bool(expr)'
16858  arg1 = compile(ss2,se,depth1,0,is_single);
16859  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_bool,arg1);
16860  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant((bool)mem[arg1]);
16861  _cimg_mp_scalar1(mp_bool,arg1);
16862  }
16863  arg1 = compile(ss1,se,depth1,0,is_single);
16864  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_logical_not,arg1);
16865  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(!mem[arg1]);
16866  _cimg_mp_scalar1(mp_logical_not,arg1);
16867  }
16868 
16869  if (*ss=='~') { // Bitwise not ('~')
16870  _cimg_mp_op("Operator '~'");
16871  arg1 = compile(ss1,se,depth1,0,is_single);
16872  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_bitwise_not,arg1);
16873  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(~(unsigned int)mem[arg1]);
16874  _cimg_mp_scalar1(mp_bitwise_not,arg1);
16875  }
16876  }
16877 
16878  for (s = se3, ns = se2; s>ss; --s, --ns)
16879  if (*s=='^' && *ns=='^' && level[s - expr._data]==clevel) { // Complex power ('^^')
16880  _cimg_mp_op("Operator '^^'");
16881  arg1 = compile(ss,s,depth1,0,is_single);
16882  arg2 = compile(s + 2,se,depth1,0,is_single);
16883  _cimg_mp_check_type(arg1,1,3,2);
16884  _cimg_mp_check_type(arg2,2,3,2);
16885  if (arg2==1) _cimg_mp_return(arg1);
16886  pos = vector(2);
16887  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) {
16888  CImg<ulongT>::vector((ulongT)mp_complex_pow_vv,pos,arg1,arg2).move_to(code);
16889  _cimg_mp_return(pos);
16890  }
16891  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) {
16892  CImg<ulongT>::vector((ulongT)mp_complex_pow_vs,pos,arg1,arg2).move_to(code);
16893  _cimg_mp_return(pos);
16894  }
16895  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) {
16896  CImg<ulongT>::vector((ulongT)mp_complex_pow_sv,pos,arg1,arg2).move_to(code);
16897  _cimg_mp_return(pos);
16898  }
16899  CImg<ulongT>::vector((ulongT)mp_complex_pow_ss,pos,arg1,arg2).move_to(code);
16900  _cimg_mp_return(pos);
16901  }
16902 
16903  for (s = se2; s>ss; --s)
16904  if (*s=='^' && level[s - expr._data]==clevel) { // Power ('^')
16905  _cimg_mp_op("Operator '^'");
16906  arg1 = compile(ss,s,depth1,0,is_single);
16907  arg2 = compile(s + 1,se,depth1,0,is_single);
16908  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
16909  if (arg2==1) _cimg_mp_return(arg1);
16910  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_pow,arg1,arg2);
16911  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_pow,arg1,arg2);
16912  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_pow,arg1,arg2);
16913  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
16914  _cimg_mp_constant(std::pow(mem[arg1],mem[arg2]));
16915  switch (arg2) {
16916  case 0 : _cimg_mp_return(1);
16917  case 2 : _cimg_mp_scalar1(mp_sqr,arg1);
16918  case 3 : _cimg_mp_scalar1(mp_pow3,arg1);
16919  case 4 : _cimg_mp_scalar1(mp_pow4,arg1);
16920  default :
16921  if (_cimg_mp_is_constant(arg2)) {
16922  if (mem[arg2]==0.5) { _cimg_mp_scalar1(mp_sqrt,arg1); }
16923  else if (mem[arg2]==0.25) { _cimg_mp_scalar1(mp_pow0_25,arg1); }
16924  }
16925  _cimg_mp_scalar2(mp_pow,arg1,arg2);
16926  }
16927  }
16928 
16929  // Percentage computation.
16930  if (*se1=='%') {
16931  arg1 = compile(ss,se1,depth1,0,is_single);
16932  arg2 = _cimg_mp_is_constant(arg1)?0:constant(100);
16933  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector2_vs(mp_div,arg1,arg2);
16934  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(mem[arg1]/100);
16935  _cimg_mp_scalar2(mp_div,arg1,arg2);
16936  }
16937 
16938  is_sth = ss1<se1 && (*ss=='+' || *ss=='-') && *ss1==*ss; // is pre-?
16939  if (is_sth || (se2>ss && (*se1=='+' || *se1=='-') && *se2==*se1)) { // Pre/post-decrement and increment
16940  if ((is_sth && *ss=='+') || (!is_sth && *se1=='+')) {
16941  _cimg_mp_op("Operator '++'");
16942  op = mp_self_increment;
16943  } else {
16944  _cimg_mp_op("Operator '--'");
16945  op = mp_self_decrement;
16946  }
16947  ref.assign(7);
16948  arg1 = is_sth?compile(ss2,se,depth1,ref,is_single):
16949  compile(ss,se2,depth1,ref,is_single); // Variable slot
16950 
16951  // Apply operator on a copy to prevent modifying a constant or a variable.
16952  if (*ref && (_cimg_mp_is_constant(arg1) || _cimg_mp_is_vector(arg1) || _cimg_mp_is_variable(arg1))) {
16953  if (_cimg_mp_is_vector(arg1)) arg1 = vector_copy(arg1);
16954  else arg1 = scalar1(mp_copy,arg1);
16955  }
16956 
16957  if (is_sth) pos = arg1; // Determine return indice, depending on pre/post action
16958  else {
16959  if (_cimg_mp_is_vector(arg1)) pos = vector_copy(arg1);
16960  else pos = scalar1(mp_copy,arg1);
16961  }
16962 
16963  if (*ref==1) { // Vector value (scalar): V[k]++
16964  arg3 = ref[1]; // Vector slot
16965  arg4 = ref[2]; // Index
16966  if (is_sth && p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
16967  CImg<ulongT>::vector((ulongT)op,arg1,1).move_to(code);
16968  CImg<ulongT>::vector((ulongT)mp_vector_set_off,arg1,arg3,(ulongT)_cimg_mp_size(arg3),arg4,arg1).
16969  move_to(code);
16970  _cimg_mp_return(pos);
16971  }
16972 
16973  if (*ref==2) { // Image value (scalar): i/j[_#ind,off]++
16974  if (!is_single) is_parallelizable = false;
16975  p1 = ref[1]; // Index
16976  is_relative = (bool)ref[2];
16977  arg3 = ref[3]; // Offset
16978  if (is_sth && p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
16979  CImg<ulongT>::vector((ulongT)op,arg1).move_to(code);
16980  if (p1!=~0U) {
16981  if (!listout) _cimg_mp_return(pos);
16982  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_joff:mp_list_set_ioff),
16983  arg1,p1,arg3).move_to(code);
16984  } else {
16985  if (!imgout) _cimg_mp_return(pos);
16986  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_joff:mp_set_ioff),
16987  arg1,arg3).move_to(code);
16988  }
16989  _cimg_mp_return(pos);
16990  }
16991 
16992  if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c)++
16993  if (!is_single) is_parallelizable = false;
16994  p1 = ref[1]; // Index
16995  is_relative = (bool)ref[2];
16996  arg3 = ref[3]; // X
16997  arg4 = ref[4]; // Y
16998  arg5 = ref[5]; // Z
16999  arg6 = ref[6]; // C
17000  if (is_sth && p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
17001  CImg<ulongT>::vector((ulongT)op,arg1).move_to(code);
17002  if (p1!=~0U) {
17003  if (!listout) _cimg_mp_return(pos);
17004  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc),
17005  arg1,p1,arg3,arg4,arg5,arg6).move_to(code);
17006  } else {
17007  if (!imgout) _cimg_mp_return(pos);
17008  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_jxyzc:mp_set_ixyzc),
17009  arg1,arg3,arg4,arg5,arg6).move_to(code);
17010  }
17011  _cimg_mp_return(pos);
17012  }
17013 
17014  if (*ref==4) { // Image value (vector): I/J[_#ind,off]++
17015  if (!is_single) is_parallelizable = false;
17016  p1 = ref[1]; // Index
17017  is_relative = (bool)ref[2];
17018  arg3 = ref[3]; // Offset
17019  if (is_sth && p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
17020  self_vector_s(arg1,op==mp_self_increment?mp_self_add:mp_self_sub,1);
17021  if (p1!=~0U) {
17022  if (!listout) _cimg_mp_return(pos);
17023  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v),
17024  arg1,p1,arg3,_cimg_mp_size(arg1)).move_to(code);
17025  } else {
17026  if (!imgout) _cimg_mp_return(pos);
17027  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v),
17028  arg1,arg3,_cimg_mp_size(arg1)).move_to(code);
17029  }
17030  _cimg_mp_return(pos);
17031  }
17032 
17033  if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c)++
17034  if (!is_single) is_parallelizable = false;
17035  p1 = ref[1]; // Index
17036  is_relative = (bool)ref[2];
17037  arg3 = ref[3]; // X
17038  arg4 = ref[4]; // Y
17039  arg5 = ref[5]; // Z
17040  if (is_sth && p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
17041  self_vector_s(arg1,op==mp_self_increment?mp_self_add:mp_self_sub,1);
17042  if (p1!=~0U) {
17043  if (!listout) _cimg_mp_return(pos);
17044  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v),
17045  arg1,p1,arg3,arg4,arg5,_cimg_mp_size(arg1)).move_to(code);
17046  } else {
17047  if (!imgout) _cimg_mp_return(pos);
17048  CImg<ulongT>::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v),
17049  arg1,arg3,arg4,arg5,_cimg_mp_size(arg1)).move_to(code);
17050  }
17051  _cimg_mp_return(pos);
17052  }
17053 
17054  if (_cimg_mp_is_vector(arg1)) { // Vector variable: V++
17055  self_vector_s(arg1,op==mp_self_increment?mp_self_add:mp_self_sub,1);
17056  _cimg_mp_return(pos);
17057  }
17058 
17059  if (_cimg_mp_is_variable(arg1)) { // Scalar variable: s++
17060  CImg<ulongT>::vector((ulongT)op,arg1).move_to(code);
17061  _cimg_mp_return(pos);
17062  }
17063 
17064  if (is_sth) variable_name.assign(ss2,(unsigned int)(se - ss1));
17065  else variable_name.assign(ss,(unsigned int)(se1 - ss));
17066  variable_name.back() = 0;
17067  cimg::strpare(variable_name,false,true);
17068  *se = saved_char;
17069  cimg::strellipsize(variable_name,64);
17070  s0 = ss - 4>expr._data?ss - 4:expr._data;
17071  cimg::strellipsize(s0,64);
17072  throw CImgArgumentException("[" cimg_appname "_math_parser] "
17073  "CImg<%s>::%s: %s: Invalid %slvalue '%s', "
17074  "in expression '%s%s%s'.",
17075  pixel_type(),_cimg_mp_calling_function,s_op,
17076  _cimg_mp_is_constant(arg1)?"const ":"",
17077  variable_name._data,
17078  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
17079  }
17080 
17081  // Array-like access to vectors and image values 'i/j/I/J[_#ind,offset,_boundary]' and 'vector[offset]'.
17082  if (*se1==']' && *ss!='[') {
17083  _cimg_mp_op("Value accessor '[]'");
17084  is_relative = *ss=='j' || *ss=='J';
17085  s0 = s1 = std::strchr(ss,'['); if (s0) { do { --s1; } while ((signed char)*s1<=' '); cimg::swap(*s0,*++s1); }
17086 
17087  if ((*ss=='I' || *ss=='J') && *ss1=='[' &&
17088  (reserved_label[*ss]==~0U || !_cimg_mp_is_vector(reserved_label[*ss]))) { // Image value as a vector
17089  if (*ss2=='#') { // Index specified
17090  s0 = ss3; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
17091  p1 = compile(ss3,s0++,depth1,0,is_single);
17092  _cimg_mp_check_list(false);
17093  } else { p1 = ~0U; s0 = ss2; }
17094  s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
17095  p2 = 1 + (p1!=~0U);
17096  arg1 = compile(s0,s1,depth1,0,is_single); // Offset
17097  _cimg_mp_check_type(arg1,p2,1,0);
17098  arg2 = ~0U;
17099  if (s1<se1) {
17100  arg2 = compile(++s1,se1,depth1,0,is_single); // Boundary
17101  _cimg_mp_check_type(arg2,p2 + 1,1,0);
17102  }
17103  if (p_ref && arg2==~0U) {
17104  *p_ref = 4;
17105  p_ref[1] = p1;
17106  p_ref[2] = (unsigned int)is_relative;
17107  p_ref[3] = arg1;
17108  if (p1!=~0U && _cimg_mp_is_comp(p1)) memtype[p1] = -2; // Prevent from being used in further optimization
17109  if (_cimg_mp_is_comp(arg1)) memtype[arg1] = -2;
17110  }
17111  p2 = ~0U; // 'p2' must be the dimension of the vector-valued operand if any
17112  if (p1==~0U) p2 = imgin._spectrum;
17113  else if (_cimg_mp_is_constant(p1)) {
17114  p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width());
17115  p2 = listin[p3]._spectrum;
17116  }
17117  _cimg_mp_check_vector0(p2);
17118  pos = vector(p2);
17119  if (p1!=~0U) {
17120  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_Joff:mp_list_Ioff),
17121  pos,p1,arg1,arg2==~0U?_cimg_mp_boundary:arg2,p2).move_to(code);
17122  } else {
17123  need_input_copy = true;
17124  CImg<ulongT>::vector((ulongT)(is_relative?mp_Joff:mp_Ioff),
17125  pos,arg1,arg2==~0U?_cimg_mp_boundary:arg2,p2).move_to(code);
17126  }
17127  _cimg_mp_return(pos);
17128  }
17129 
17130  if ((*ss=='i' || *ss=='j') && *ss1=='[' &&
17131  (reserved_label[*ss]==~0U || !_cimg_mp_is_vector(reserved_label[*ss]))) { // Image value as a scalar
17132  if (*ss2=='#') { // Index specified
17133  s0 = ss3; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
17134  p1 = compile(ss3,s0++,depth1,0,is_single);
17135  } else { p1 = ~0U; s0 = ss2; }
17136  s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
17137  arg1 = compile(s0,s1,depth1,0,is_single); // Offset
17138  arg2 = s1<se1?compile(++s1,se1,depth1,0,is_single):~0U; // Boundary
17139  if (p_ref && arg2==~0U) {
17140  *p_ref = 2;
17141  p_ref[1] = p1;
17142  p_ref[2] = (unsigned int)is_relative;
17143  p_ref[3] = arg1;
17144  if (p1!=~0U && _cimg_mp_is_comp(p1)) memtype[p1] = -2; // Prevent from being used in further optimization
17145  if (_cimg_mp_is_comp(arg1)) memtype[arg1] = -2;
17146  }
17147  if (p1!=~0U) {
17148  if (!listin) _cimg_mp_return(0);
17149  pos = scalar3(is_relative?mp_list_joff:mp_list_ioff,p1,arg1,arg2==~0U?_cimg_mp_boundary:arg2);
17150  } else {
17151  if (!imgin) _cimg_mp_return(0);
17152  need_input_copy = true;
17153  pos = scalar2(is_relative?mp_joff:mp_ioff,arg1,arg2==~0U?_cimg_mp_boundary:arg2);
17154  }
17155  memtype[pos] = -2; // Prevent from being used in further optimization
17156  _cimg_mp_return(pos);
17157  }
17158 
17159  s0 = se1; while (s0>ss && (*s0!='[' || level[s0 - expr._data]!=clevel)) --s0;
17160  if (s0>ss) { // Vector value
17161  arg1 = compile(ss,s0,depth1,0,is_single);
17162  if (_cimg_mp_is_scalar(arg1)) {
17163  variable_name.assign(ss,(unsigned int)(s0 - ss + 1)).back() = 0;
17164  *se = saved_char;
17165  cimg::strellipsize(variable_name,64);
17166  s0 = ss - 4>expr._data?ss - 4:expr._data;
17167  cimg::strellipsize(s0,64);
17168  throw CImgArgumentException("[" cimg_appname "_math_parser] "
17169  "CImg<%s>::%s: %s: Array brackets used on non-vector variable '%s', "
17170  "in expression '%s%s%s'.",
17171  pixel_type(),_cimg_mp_calling_function,s_op,
17172  variable_name._data,
17173  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
17174 
17175  }
17176  s1 = s0 + 1; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
17177 
17178  if (s1<se1) { // Two arguments -> sub-vector extraction
17179  p1 = _cimg_mp_size(arg1);
17180  arg2 = compile(++s0,s1,depth1,0,is_single); // Starting indice
17181  arg3 = compile(++s1,se1,depth1,0,is_single); // Length
17182  _cimg_mp_check_constant(arg3,2,3);
17183  arg3 = (unsigned int)mem[arg3];
17184  pos = vector(arg3);
17185  CImg<ulongT>::vector((ulongT)mp_vector_crop,pos,arg1,p1,arg2,arg3).move_to(code);
17186  _cimg_mp_return(pos);
17187  }
17188 
17189  // One argument -> vector value reference
17190  arg2 = compile(++s0,se1,depth1,0,is_single);
17191  if (_cimg_mp_is_constant(arg2)) { // Constant index
17192  nb = (int)mem[arg2];
17193  if (nb>=0 && nb<(int)_cimg_mp_size(arg1)) _cimg_mp_return(arg1 + 1 + nb);
17194  variable_name.assign(ss,(unsigned int)(s0 - ss)).back() = 0;
17195  *se = saved_char;
17196  cimg::strellipsize(variable_name,64);
17197  s0 = ss - 4>expr._data?ss - 4:expr._data;
17198  cimg::strellipsize(s0,64);
17199  throw CImgArgumentException("[" cimg_appname "_math_parser] "
17200  "CImg<%s>::%s: Out-of-bounds reference '%s[%d]' "
17201  "(vector '%s' has dimension %u), "
17202  "in expression '%s%s%s'.",
17203  pixel_type(),_cimg_mp_calling_function,
17204  variable_name._data,nb,
17205  variable_name._data,_cimg_mp_size(arg1),
17206  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
17207  }
17208  if (p_ref) {
17209  *p_ref = 1;
17210  p_ref[1] = arg1;
17211  p_ref[2] = arg2;
17212  if (_cimg_mp_is_comp(arg2)) memtype[arg2] = -2; // Prevent from being used in further optimization
17213  }
17214  pos = scalar3(mp_vector_off,arg1,_cimg_mp_size(arg1),arg2);
17215  memtype[pos] = -2; // Prevent from being used in further optimization
17216  _cimg_mp_return(pos);
17217  }
17218  }
17219 
17220  // Look for a function call, an access to image value, or a parenthesis.
17221  if (*se1==')') {
17222  if (*ss=='(') _cimg_mp_return(compile(ss1,se1,depth1,p_ref,is_single)); // Simple parentheses
17223  _cimg_mp_op("Value accessor '()'");
17224  is_relative = *ss=='j' || *ss=='J';
17225  s0 = s1 = std::strchr(ss,'('); if (s0) { do { --s1; } while ((signed char)*s1<=' '); cimg::swap(*s0,*++s1); }
17226 
17227  // I/J(_#ind,_x,_y,_z,_interpolation,_boundary_conditions)
17228  if ((*ss=='I' || *ss=='J') && *ss1=='(') { // Image value as scalar
17229  if (*ss2=='#') { // Index specified
17230  s0 = ss3; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
17231  p1 = compile(ss3,s0++,depth1,0,is_single);
17232  _cimg_mp_check_list(false);
17233  } else { p1 = ~0U; s0 = ss2; }
17234  arg1 = is_relative?0U:(unsigned int)_cimg_mp_slot_x;
17235  arg2 = is_relative?0U:(unsigned int)_cimg_mp_slot_y;
17236  arg3 = is_relative?0U:(unsigned int)_cimg_mp_slot_z;
17237  arg4 = arg5 = ~0U;
17238  if (s0<se1) {
17239  s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
17240  arg1 = compile(s0,s1,depth1,0,is_single);
17241  if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector
17242  p2 = _cimg_mp_size(arg1);
17243  ++arg1;
17244  if (p2>1) {
17245  arg2 = arg1 + 1;
17246  if (p2>2) arg3 = arg2 + 1;
17247  }
17248  if (s1<se1) {
17249  s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
17250  arg4 = compile(s1,s2,depth1,0,is_single);
17251  arg5 = s2<se1?compile(++s2,se1,depth1,0,is_single):~0U;
17252  }
17253  } else if (s1<se1) {
17254  s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
17255  arg2 = compile(s1,s2,depth1,0,is_single);
17256  if (s2<se1) {
17257  s3 = ++s2; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
17258  arg3 = compile(s2,s3,depth1,0,is_single);
17259  if (s3<se1) {
17260  s2 = ++s3; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
17261  arg4 = compile(s3,s2,depth1,0,is_single);
17262  arg5 = s2<se1?compile(++s2,se1,depth1,0,is_single):~0U;
17263  }
17264  }
17265  }
17266  }
17267  if (p_ref && arg4==~0U && arg5==~0U) {
17268  *p_ref = 5;
17269  p_ref[1] = p1;
17270  p_ref[2] = (unsigned int)is_relative;
17271  p_ref[3] = arg1;
17272  p_ref[4] = arg2;
17273  p_ref[5] = arg3;
17274  if (p1!=~0U && _cimg_mp_is_comp(p1)) memtype[p1] = -2; // Prevent from being used in further optimization
17275  if (_cimg_mp_is_comp(arg1)) memtype[arg1] = -2;
17276  if (_cimg_mp_is_comp(arg2)) memtype[arg2] = -2;
17277  if (_cimg_mp_is_comp(arg3)) memtype[arg3] = -2;
17278  }
17279  p2 = ~0U; // 'p2' must be the dimension of the vector-valued operand if any
17280  if (p1==~0U) p2 = imgin._spectrum;
17281  else if (_cimg_mp_is_constant(p1)) {
17282  p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width());
17283  p2 = listin[p3]._spectrum;
17284  }
17285  _cimg_mp_check_vector0(p2);
17286  pos = vector(p2);
17287  if (p1!=~0U)
17288  CImg<ulongT>::vector((ulongT)(is_relative?mp_list_Jxyz:mp_list_Ixyz),
17289  pos,p1,arg1,arg2,arg3,
17290  arg4==~0U?_cimg_mp_interpolation:arg4,
17291  arg5==~0U?_cimg_mp_boundary:arg5,p2).move_to(code);
17292  else {
17293  need_input_copy = true;
17294  CImg<ulongT>::vector((ulongT)(is_relative?mp_Jxyz:mp_Ixyz),
17295  pos,arg1,arg2,arg3,
17296  arg4==~0U?_cimg_mp_interpolation:arg4,
17297  arg5==~0U?_cimg_mp_boundary:arg5,p2).move_to(code);
17298  }
17299  _cimg_mp_return(pos);
17300  }
17301 
17302  // i/j(_#ind,_x,_y,_z,_c,_interpolation,_boundary_conditions)
17303  if ((*ss=='i' || *ss=='j') && *ss1=='(') { // Image value as scalar
17304  if (*ss2=='#') { // Index specified
17305  s0 = ss3; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
17306  p1 = compile(ss3,s0++,depth1,0,is_single);
17307  } else { p1 = ~0U; s0 = ss2; }
17308  arg1 = is_relative?0U:(unsigned int)_cimg_mp_slot_x;
17309  arg2 = is_relative?0U:(unsigned int)_cimg_mp_slot_y;
17310  arg3 = is_relative?0U:(unsigned int)_cimg_mp_slot_z;
17311  arg4 = is_relative?0U:(unsigned int)_cimg_mp_slot_c;
17312  arg5 = arg6 = ~0U;
17313  if (s0<se1) {
17314  s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
17315  arg1 = compile(s0,s1,depth1,0,is_single);
17316  if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector
17317  p2 = _cimg_mp_size(arg1);
17318  ++arg1;
17319  if (p2>1) {
17320  arg2 = arg1 + 1;
17321  if (p2>2) {
17322  arg3 = arg2 + 1;
17323  if (p2>3) arg4 = arg3 + 1;
17324  }
17325  }
17326  if (s1<se1) {
17327  s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
17328  arg5 = compile(s1,s2,depth1,0,is_single);
17329  arg6 = s2<se1?compile(++s2,se1,depth1,0,is_single):~0U;
17330  }
17331  } else if (s1<se1) {
17332  s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
17333  arg2 = compile(s1,s2,depth1,0,is_single);
17334  if (s2<se1) {
17335  s3 = ++s2; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
17336  arg3 = compile(s2,s3,depth1,0,is_single);
17337  if (s3<se1) {
17338  s2 = ++s3; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
17339  arg4 = compile(s3,s2,depth1,0,is_single);
17340  if (s2<se1) {
17341  s3 = ++s2; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
17342  arg5 = compile(s2,s3,depth1,0,is_single);
17343  arg6 = s3<se1?compile(++s3,se1,depth1,0,is_single):~0U;
17344  }
17345  }
17346  }
17347  }
17348  }
17349  if (p_ref && arg5==~0U && arg6==~0U) {
17350  *p_ref = 3;
17351  p_ref[1] = p1;
17352  p_ref[2] = (unsigned int)is_relative;
17353  p_ref[3] = arg1;
17354  p_ref[4] = arg2;
17355  p_ref[5] = arg3;
17356  p_ref[6] = arg4;
17357  if (p1!=~0U && _cimg_mp_is_comp(p1)) memtype[p1] = -2; // Prevent from being used in further optimization
17358  if (_cimg_mp_is_comp(arg1)) memtype[arg1] = -2;
17359  if (_cimg_mp_is_comp(arg2)) memtype[arg2] = -2;
17360  if (_cimg_mp_is_comp(arg3)) memtype[arg3] = -2;
17361  if (_cimg_mp_is_comp(arg4)) memtype[arg4] = -2;
17362  }
17363 
17364  if (p1!=~0U) {
17365  if (!listin) _cimg_mp_return(0);
17366  pos = scalar7(is_relative?mp_list_jxyzc:mp_list_ixyzc,
17367  p1,arg1,arg2,arg3,arg4,
17368  arg5==~0U?_cimg_mp_interpolation:arg5,
17369  arg6==~0U?_cimg_mp_boundary:arg6);
17370  } else {
17371  if (!imgin) _cimg_mp_return(0);
17372  need_input_copy = true;
17373  pos = scalar6(is_relative?mp_jxyzc:mp_ixyzc,
17374  arg1,arg2,arg3,arg4,
17375  arg5==~0U?_cimg_mp_interpolation:arg5,
17376  arg6==~0U?_cimg_mp_boundary:arg6);
17377  }
17378  memtype[pos] = -2; // Prevent from being used in further optimization
17379  _cimg_mp_return(pos);
17380  }
17381 
17382  // Mathematical functions.
17383  switch (*ss) {
17384 
17385  case '_' :
17386  if (*ss1=='(') // Skip arguments
17387  _cimg_mp_return_nan();
17388  break;
17389 
17390  case 'a' :
17391  if (!std::strncmp(ss,"abs(",4)) { // Absolute value
17392  _cimg_mp_op("Function 'abs()'");
17393  arg1 = compile(ss4,se1,depth1,0,is_single);
17394  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_abs,arg1);
17395  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::abs(mem[arg1]));
17396  _cimg_mp_scalar1(mp_abs,arg1);
17397  }
17398 
17399  if (!std::strncmp(ss,"acos(",5)) { // Arccos
17400  _cimg_mp_op("Function 'acos()'");
17401  arg1 = compile(ss5,se1,depth1,0,is_single);
17402  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_acos,arg1);
17403  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::acos(mem[arg1]));
17404  _cimg_mp_scalar1(mp_acos,arg1);
17405  }
17406 
17407  if (!std::strncmp(ss,"arg(",4)) { // Nth argument
17408  _cimg_mp_op("Function 'arg()'");
17409  s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
17410  arg1 = compile(ss4,s1,depth1,0,is_single);
17411  _cimg_mp_check_type(arg1,1,1,0);
17412  s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
17413  arg2 = compile(s1,s2,depth1,0,is_single);
17414  p2 = _cimg_mp_size(arg2);
17415  p3 = 3;
17416  CImg<ulongT>::vector((ulongT)mp_arg,0,0,p2,arg1,arg2).move_to(_opcode);
17417  for (s = ++s2; s<se; ++s) {
17418  ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
17419  (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
17420  arg3 = compile(s,ns,depth1,0,is_single);
17421  _cimg_mp_check_type(arg3,p3,p2?2:1,p2);
17422  CImg<ulongT>::vector(arg3).move_to(_opcode);
17423  ++p3;
17424  s = ns;
17425  }
17426  (_opcode>'y').move_to(opcode);
17427  opcode[2] = opcode._height;
17428  if (_cimg_mp_is_constant(arg1)) {
17429  p3-=1; // Number of args
17430  arg1 = (unsigned int)(mem[arg1]<0?mem[arg1] + p3:mem[arg1]);
17431  if (arg1<p3) _cimg_mp_return(opcode[4 + arg1]);
17432  if (p2) {
17433  pos = vector(p2);
17434  std::memset(&mem[pos] + 1,0,p2*sizeof(double));
17435  _cimg_mp_return(pos);
17436  } else _cimg_mp_return(0);
17437  }
17438  pos = opcode[1] = p2?vector(p2):scalar();
17439  opcode.move_to(code);
17440  _cimg_mp_return(pos);
17441  }
17442 
17443  if (!std::strncmp(ss,"asin(",5)) { // Arcsin
17444  _cimg_mp_op("Function 'asin()'");
17445  arg1 = compile(ss5,se1,depth1,0,is_single);
17446  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_asin,arg1);
17447  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::asin(mem[arg1]));
17448  _cimg_mp_scalar1(mp_asin,arg1);
17449  }
17450 
17451  if (!std::strncmp(ss,"atan(",5)) { // Arctan
17452  _cimg_mp_op("Function 'atan()'");
17453  arg1 = compile(ss5,se1,depth1,0,is_single);
17454  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_atan,arg1);
17455  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::atan(mem[arg1]));
17456  _cimg_mp_scalar1(mp_atan,arg1);
17457  }
17458 
17459  if (!std::strncmp(ss,"atan2(",6)) { // Arctan2
17460  _cimg_mp_op("Function 'atan2()'");
17461  s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
17462  arg1 = compile(ss6,s1,depth1,0,is_single);
17463  arg2 = compile(++s1,se1,depth1,0,is_single);
17464  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
17465  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_atan2,arg1,arg2);
17466  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_atan2,arg1,arg2);
17467  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_atan2,arg1,arg2);
17468  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
17469  _cimg_mp_constant(std::atan2(mem[arg1],mem[arg2]));
17470  _cimg_mp_scalar2(mp_atan2,arg1,arg2);
17471  }
17472  break;
17473 
17474  case 'b' :
17475  if (!std::strncmp(ss,"bool(",5)) { // Boolean cast
17476  _cimg_mp_op("Function 'bool()'");
17477  arg1 = compile(ss5,se1,depth1,0,is_single);
17478  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_bool,arg1);
17479  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant((bool)mem[arg1]);
17480  _cimg_mp_scalar1(mp_bool,arg1);
17481  }
17482 
17483  if (!std::strncmp(ss,"break(",6)) { // Complex absolute value
17484  if (pexpr[se2 - expr._data]=='(') { // no arguments?
17485  CImg<ulongT>::vector((ulongT)mp_break,_cimg_mp_slot_nan).move_to(code);
17486  _cimg_mp_return_nan();
17487  }
17488  }
17489 
17490  if (!std::strncmp(ss,"breakpoint(",11)) { // Break point (for abort test)
17491  _cimg_mp_op("Function 'breakpoint()'");
17492  if (pexpr[se2 - expr._data]=='(') { // no arguments?
17493  CImg<ulongT>::vector((ulongT)mp_breakpoint,_cimg_mp_slot_nan).move_to(code);
17494  _cimg_mp_return_nan();
17495  }
17496  }
17497  break;
17498 
17499  case 'c' :
17500  if (!std::strncmp(ss,"cabs(",5)) { // Complex absolute value
17501  _cimg_mp_op("Function 'cabs()'");
17502  arg1 = compile(ss5,se1,depth1,0,is_single);
17503  _cimg_mp_check_type(arg1,0,2,2);
17504  _cimg_mp_scalar2(mp_complex_abs,arg1 + 1,arg1 + 2);
17505  }
17506 
17507  if (!std::strncmp(ss,"carg(",5)) { // Complex argument
17508  _cimg_mp_op("Function 'carg()'");
17509  arg1 = compile(ss5,se1,depth1,0,is_single);
17510  _cimg_mp_check_type(arg1,0,2,2);
17511  _cimg_mp_scalar2(mp_atan2,arg1 + 2,arg1 + 1);
17512  }
17513 
17514  if (!std::strncmp(ss,"cats(",5)) { // Concatenate strings
17515  _cimg_mp_op("Function 'cats()'");
17516  CImg<ulongT>::vector((ulongT)mp_cats,0,0,0).move_to(_opcode);
17517  arg1 = 0;
17518  for (s = ss5; s<se; ++s) {
17519  ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
17520  (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
17521  arg1 = compile(s,ns,depth1,0,is_single);
17522  CImg<ulongT>::vector(arg1,_cimg_mp_size(arg1)).move_to(_opcode);
17523  s = ns;
17524  }
17525  _cimg_mp_check_constant(arg1,1,3); // Last argument = output vector size
17526  _opcode.remove();
17527  (_opcode>'y').move_to(opcode);
17528  p1 = (unsigned int)mem[arg1];
17529  pos = vector(p1);
17530  opcode[1] = pos;
17531  opcode[2] = p1;
17532  opcode[3] = opcode._height;
17533  opcode.move_to(code);
17534  _cimg_mp_return(pos);
17535  }
17536 
17537  if (!std::strncmp(ss,"cbrt(",5)) { // Cubic root
17538  _cimg_mp_op("Function 'cbrt()'");
17539  arg1 = compile(ss5,se1,depth1,0,is_single);
17540  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cbrt,arg1);
17541  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::cbrt(mem[arg1]));
17542  _cimg_mp_scalar1(mp_cbrt,arg1);
17543  }
17544 
17545  if (!std::strncmp(ss,"cconj(",6)) { // Complex conjugate
17546  _cimg_mp_op("Function 'cconj()'");
17547  arg1 = compile(ss6,se1,depth1,0,is_single);
17548  _cimg_mp_check_type(arg1,0,2,2);
17549  pos = vector(2);
17550  CImg<ulongT>::vector((ulongT)mp_complex_conj,pos,arg1).move_to(code);
17551  _cimg_mp_return(pos);
17552  }
17553 
17554  if (!std::strncmp(ss,"ceil(",5)) { // Ceil
17555  _cimg_mp_op("Function 'ceil()'");
17556  arg1 = compile(ss5,se1,depth1,0,is_single);
17557  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_ceil,arg1);
17558  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::ceil(mem[arg1]));
17559  _cimg_mp_scalar1(mp_ceil,arg1);
17560  }
17561 
17562  if (!std::strncmp(ss,"cexp(",5)) { // Complex exponential
17563  _cimg_mp_op("Function 'cexp()'");
17564  arg1 = compile(ss5,se1,depth1,0,is_single);
17565  _cimg_mp_check_type(arg1,0,2,2);
17566  pos = vector(2);
17567  CImg<ulongT>::vector((ulongT)mp_complex_exp,pos,arg1).move_to(code);
17568  _cimg_mp_return(pos);
17569  }
17570 
17571  if (!std::strncmp(ss,"clog(",5)) { // Complex logarithm
17572  _cimg_mp_op("Function 'clog()'");
17573  arg1 = compile(ss5,se1,depth1,0,is_single);
17574  _cimg_mp_check_type(arg1,0,2,2);
17575  pos = vector(2);
17576  CImg<ulongT>::vector((ulongT)mp_complex_log,pos,arg1).move_to(code);
17577  _cimg_mp_return(pos);
17578  }
17579 
17580  if (!std::strncmp(ss,"continue(",9)) { // Complex absolute value
17581  if (pexpr[se2 - expr._data]=='(') { // no arguments?
17582  CImg<ulongT>::vector((ulongT)mp_continue,_cimg_mp_slot_nan).move_to(code);
17583  _cimg_mp_return_nan();
17584  }
17585  }
17586 
17587  if (!std::strncmp(ss,"copy(",5)) { // Memory copy
17588  _cimg_mp_op("Function 'copy()'");
17589  ref.assign(14);
17590  s1 = ss5; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
17591  arg1 = p1 = compile(ss5,s1,depth1,ref,is_single);
17592  s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
17593  arg2 = compile(s1,s2,depth1,ref._data + 7,is_single);
17594  arg3 = ~0U; arg4 = arg5 = arg6 = 1;
17595  if (s2<se1) {
17596  s3 = ++s2; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
17597  arg3 = compile(s2,s3,depth1,0,is_single);
17598  if (s3<se1) {
17599  s1 = ++s3; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
17600  arg4 = compile(s3,s1,depth1,0,is_single);
17601  if (s1<se1) {
17602  s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
17603  arg5 = compile(s1,s2,depth1,0,is_single);
17604  arg6 = s2<se1?compile(++s2,se1,depth1,0,is_single):1;
17605  }
17606  }
17607  }
17608  if (_cimg_mp_is_vector(arg1) && !ref[0]) ++arg1;
17609  if (_cimg_mp_is_vector(arg2)) {
17610  if (arg3==~0U) arg3 = _cimg_mp_size(arg2);
17611  if (!ref[7]) ++arg2;
17612  }
17613  if (arg3==~0U) arg3 = 1;
17614  _cimg_mp_check_type(arg3,3,1,0);
17615  _cimg_mp_check_type(arg4,4,1,0);
17616  _cimg_mp_check_type(arg5,5,1,0);
17617  _cimg_mp_check_type(arg6,5,1,0);
17618  CImg<ulongT>(1,22).move_to(code);
17619  code.back().get_shared_rows(0,7).fill((ulongT)mp_memcopy,p1,arg1,arg2,arg3,arg4,arg5,arg6);
17620  code.back().get_shared_rows(8,21).fill(ref);
17621  _cimg_mp_return(p1);
17622  }
17623 
17624  if (!std::strncmp(ss,"cos(",4)) { // Cosine
17625  _cimg_mp_op("Function 'cos()'");
17626  arg1 = compile(ss4,se1,depth1,0,is_single);
17627  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cos,arg1);
17628  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::cos(mem[arg1]));
17629  _cimg_mp_scalar1(mp_cos,arg1);
17630  }
17631 
17632  if (!std::strncmp(ss,"cosh(",5)) { // Hyperbolic cosine
17633  _cimg_mp_op("Function 'cosh()'");
17634  arg1 = compile(ss5,se1,depth1,0,is_single);
17635  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cosh,arg1);
17636  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::cosh(mem[arg1]));
17637  _cimg_mp_scalar1(mp_cosh,arg1);
17638  }
17639 
17640  if (!std::strncmp(ss,"critical(",9)) { // Critical section (single thread at a time)
17641  _cimg_mp_op("Function 'critical()'");
17642  p1 = code._width;
17643  arg1 = compile(ss + 9,se1,depth1,p_ref,true);
17644  CImg<ulongT>::vector((ulongT)mp_critical,arg1,code._width - p1).move_to(code,p1);
17645  _cimg_mp_return(arg1);
17646  }
17647 
17648  if (!std::strncmp(ss,"crop(",5)) { // Image crop
17649  _cimg_mp_op("Function 'crop()'");
17650  if (*ss5=='#') { // Index specified
17651  s0 = ss6; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
17652  p1 = compile(ss6,s0++,depth1,0,is_single);
17653  _cimg_mp_check_list(false);
17654  } else { p1 = ~0U; s0 = ss5; need_input_copy = true; }
17655  pos = 0;
17656  is_sth = false; // Coordinates specified as a vector?
17657  if (ss5<se1) for (s = s0; s<se; ++s, ++pos) {
17658  ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
17659  (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
17660  arg1 = compile(s,ns,depth1,0,is_single);
17661  if (!pos && _cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector
17662  opcode = CImg<ulongT>::sequence(_cimg_mp_size(arg1),arg1 + 1,
17663  arg1 + (ulongT)_cimg_mp_size(arg1));
17664  opcode.resize(1,std::min(opcode._height,4U),1,1,0).move_to(_opcode);
17665  is_sth = true;
17666  } else {
17667  _cimg_mp_check_type(arg1,pos + 1,1,0);
17668  CImg<ulongT>::vector(arg1).move_to(_opcode);
17669  }
17670  s = ns;
17671  }
17672  (_opcode>'y').move_to(opcode);
17673 
17674  arg1 = 0; arg2 = (p1!=~0U);
17675  switch (opcode._height) {
17676  case 0 : case 1 :
17677  CImg<ulongT>::vector(0,0,0,0,~0U,~0U,~0U,~0U,0).move_to(opcode);
17678  break;
17679  case 2 :
17680  CImg<ulongT>::vector(*opcode,0,0,0,opcode[1],~0U,~0U,~0U,_cimg_mp_boundary).move_to(opcode);
17681  arg1 = arg2?3:2;
17682  break;
17683  case 3 :
17684  CImg<ulongT>::vector(*opcode,0,0,0,opcode[1],~0U,~0U,~0U,opcode[2]).move_to(opcode);
17685  arg1 = arg2?3:2;
17686  break;
17687  case 4 :
17688  CImg<ulongT>::vector(*opcode,opcode[1],0,0,opcode[2],opcode[3],~0U,~0U,_cimg_mp_boundary).
17689  move_to(opcode);
17690  arg1 = (is_sth?2:1) + arg2;
17691  break;
17692  case 5 :
17693  CImg<ulongT>::vector(*opcode,opcode[1],0,0,opcode[2],opcode[3],~0U,~0U,opcode[4]).
17694  move_to(opcode);
17695  arg1 = (is_sth?2:1) + arg2;
17696  break;
17697  case 6 :
17698  CImg<ulongT>::vector(*opcode,opcode[1],opcode[2],0,opcode[3],opcode[4],opcode[5],~0U,
17699  _cimg_mp_boundary).move_to(opcode);
17700  arg1 = (is_sth?2:4) + arg2;
17701  break;
17702  case 7 :
17703  CImg<ulongT>::vector(*opcode,opcode[1],opcode[2],0,opcode[3],opcode[4],opcode[5],~0U,
17704  opcode[6]).move_to(opcode);
17705  arg1 = (is_sth?2:4) + arg2;
17706  break;
17707  case 8 :
17708  CImg<ulongT>::vector(*opcode,opcode[1],opcode[2],opcode[3],opcode[4],opcode[5],opcode[6],
17709  opcode[7],_cimg_mp_boundary).move_to(opcode);
17710  arg1 = (is_sth?2:5) + arg2;
17711  break;
17712  case 9 :
17713  arg1 = (is_sth?2:5) + arg2;
17714  break;
17715  default : // Error -> too much arguments
17716  *se = saved_char;
17717  s0 = ss - 4>expr._data?ss - 4:expr._data;
17718  cimg::strellipsize(s0,64);
17719  throw CImgArgumentException("[" cimg_appname "_math_parser] "
17720  "CImg<%s>::%s: %s: Too much arguments specified, "
17721  "in expression '%s%s%s'.",
17722  pixel_type(),_cimg_mp_calling_function,s_op,
17723  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
17724  }
17725 
17726  _cimg_mp_check_type((unsigned int)*opcode,arg2 + 1,1,0);
17727  _cimg_mp_check_type((unsigned int)opcode[1],arg2 + 1 + (is_sth?0:1),1,0);
17728  _cimg_mp_check_type((unsigned int)opcode[2],arg2 + 1 + (is_sth?0:2),1,0);
17729  _cimg_mp_check_type((unsigned int)opcode[3],arg2 + 1 + (is_sth?0:3),1,0);
17730  if (opcode[4]!=(ulongT)~0U) {
17731  _cimg_mp_check_constant((unsigned int)opcode[4],arg1,3);
17732  opcode[4] = (ulongT)mem[opcode[4]];
17733  }
17734  if (opcode[5]!=(ulongT)~0U) {
17735  _cimg_mp_check_constant((unsigned int)opcode[5],arg1 + 1,3);
17736  opcode[5] = (ulongT)mem[opcode[5]];
17737  }
17738  if (opcode[6]!=(ulongT)~0U) {
17739  _cimg_mp_check_constant((unsigned int)opcode[6],arg1 + 2,3);
17740  opcode[6] = (ulongT)mem[opcode[6]];
17741  }
17742  if (opcode[7]!=(ulongT)~0U) {
17743  _cimg_mp_check_constant((unsigned int)opcode[7],arg1 + 3,3);
17744  opcode[7] = (ulongT)mem[opcode[7]];
17745  }
17746  _cimg_mp_check_type((unsigned int)opcode[8],arg1 + 4,1,0);
17747 
17748  if (opcode[4]==(ulongT)~0U || opcode[5]==(ulongT)~0U ||
17749  opcode[6]==(ulongT)~0U || opcode[7]==(ulongT)~0U) {
17750  if (p1!=~0U) {
17751  _cimg_mp_check_constant(p1,1,1);
17752  p1 = (unsigned int)cimg::mod((int)mem[p1],listin.width());
17753  }
17754  const CImg<T> &img = p1!=~0U?listin[p1]:imgin;
17755  if (!img) {
17756  *se = saved_char;
17757  s0 = ss - 4>expr._data?ss - 4:expr._data;
17758  cimg::strellipsize(s0,64);
17759  throw CImgArgumentException("[" cimg_appname "_math_parser] "
17760  "CImg<%s>::%s: %s: Cannot crop empty image when "
17761  "some xyzc-coordinates are unspecified, in expression '%s%s%s'.",
17762  pixel_type(),_cimg_mp_calling_function,s_op,
17763  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
17764  }
17765  if (opcode[4]==(ulongT)~0U) opcode[4] = (ulongT)img._width;
17766  if (opcode[5]==(ulongT)~0U) opcode[5] = (ulongT)img._height;
17767  if (opcode[6]==(ulongT)~0U) opcode[6] = (ulongT)img._depth;
17768  if (opcode[7]==(ulongT)~0U) opcode[7] = (ulongT)img._spectrum;
17769  }
17770 
17771  pos = vector((unsigned int)(opcode[4]*opcode[5]*opcode[6]*opcode[7]));
17772  CImg<ulongT>::vector((ulongT)mp_crop,
17773  pos,p1,
17774  *opcode,opcode[1],opcode[2],opcode[3],
17775  opcode[4],opcode[5],opcode[6],opcode[7],
17776  opcode[8]).move_to(code);
17777  _cimg_mp_return(pos);
17778  }
17779 
17780  if (!std::strncmp(ss,"cross(",6)) { // Cross product
17781  _cimg_mp_op("Function 'cross()'");
17782  s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
17783  arg1 = compile(ss6,s1,depth1,0,is_single);
17784  arg2 = compile(++s1,se1,depth1,0,is_single);
17785  _cimg_mp_check_type(arg1,1,2,3);
17786  _cimg_mp_check_type(arg2,2,2,3);
17787  pos = vector(3);
17788  CImg<ulongT>::vector((ulongT)mp_cross,pos,arg1,arg2).move_to(code);
17789  _cimg_mp_return(pos);
17790  }
17791 
17792  if (!std::strncmp(ss,"cut(",4)) { // Cut
17793  _cimg_mp_op("Function 'cut()'");
17794  s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
17795  arg1 = compile(ss4,s1,depth1,0,is_single);
17796  s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
17797  arg2 = compile(++s1,s2,depth1,0,is_single);
17798  arg3 = compile(++s2,se1,depth1,0,is_single);
17799  _cimg_mp_check_type(arg2,2,1,0);
17800  _cimg_mp_check_type(arg3,3,1,0);
17801  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector3_vss(mp_cut,arg1,arg2,arg3);
17802  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2) && _cimg_mp_is_constant(arg3)) {
17803  val = mem[arg1];
17804  val1 = mem[arg2];
17805  val2 = mem[arg3];
17806  _cimg_mp_constant(val<val1?val1:val>val2?val2:val);
17807  }
17808  _cimg_mp_scalar3(mp_cut,arg1,arg2,arg3);
17809  }
17810  break;
17811 
17812  case 'd' :
17813  if (*ss1=='(') { // Image depth
17814  _cimg_mp_op("Function 'd()'");
17815  if (*ss2=='#') { // Index specified
17816  p1 = compile(ss3,se1,depth1,0,is_single);
17817  _cimg_mp_check_list(false);
17818  } else { if (ss2!=se1) break; p1 = ~0U; }
17819  pos = scalar();
17820  CImg<ulongT>::vector((ulongT)mp_image_d,pos,p1).move_to(code);
17821  _cimg_mp_return(pos);
17822  }
17823 
17824  if (!std::strncmp(ss,"date(",5)) { // Current date or file date
17825  _cimg_mp_op("Function 'date()'");
17826  s1 = ss5; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
17827  arg1 = ss5!=se1?compile(ss5,s1,depth1,0,is_single):~0U;
17828  is_sth = s1++!=se1; // is_filename
17829  pos = arg1==~0U || _cimg_mp_is_vector(arg1)?vector(arg1==~0U?7:_cimg_mp_size(arg1)):scalar();
17830  if (is_sth) {
17831  *se1 = 0;
17832  variable_name.assign(CImg<charT>::string(s1,true,true).unroll('y'),true);
17833  cimg::strpare(variable_name,false,true);
17834  ((CImg<ulongT>::vector((ulongT)mp_date,pos,0,arg1,_cimg_mp_size(pos)),variable_name)>'y').
17835  move_to(opcode);
17836  *se1 = ')';
17837  } else
17838  CImg<ulongT>::vector((ulongT)mp_date,pos,0,arg1,_cimg_mp_size(pos)).move_to(opcode);
17839  opcode[2] = opcode._height;
17840  opcode.move_to(code);
17841  _cimg_mp_return(pos);
17842  }
17843 
17844  if (!std::strncmp(ss,"debug(",6)) { // Print debug info
17845  _cimg_mp_op("Function 'debug()'");
17846  p1 = code._width;
17847  arg1 = compile(ss6,se1,depth1,p_ref,is_single);
17848  *se1 = 0;
17849  variable_name.assign(CImg<charT>::string(ss6,true,true).unroll('y'),true);
17850  cimg::strpare(variable_name,false,true);
17851  ((CImg<ulongT>::vector((ulongT)mp_debug,arg1,0,code._width - p1),
17852  variable_name)>'y').move_to(opcode);
17853  opcode[2] = opcode._height;
17854  opcode.move_to(code,p1);
17855  *se1 = ')';
17856  _cimg_mp_return(arg1);
17857  }
17858 
17859  if (!std::strncmp(ss,"display(",8)) { // Display memory, vector or image
17860  _cimg_mp_op("Function 'display()'");
17861  if (pexpr[se2 - expr._data]=='(') { // no arguments?
17862  CImg<ulongT>::vector((ulongT)mp_display_memory,_cimg_mp_slot_nan).move_to(code);
17863  _cimg_mp_return_nan();
17864  }
17865  if (*ss8!='#') { // Vector
17866  s1 = ss8; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
17867  arg1 = compile(ss8,s1,depth1,0,is_single);
17868  arg2 = 0; arg3 = arg4 = arg5 = 1;
17869  if (s1<se1) {
17870  s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
17871  arg2 = compile(s1 + 1,s2,depth1,0,is_single);
17872  if (s2<se1) {
17873  s3 = ++s2; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
17874  arg3 = compile(s2,s3,depth1,0,is_single);
17875  if (s3<se1) {
17876  s2 = ++s3; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
17877  arg4 = compile(s3,s2,depth1,0,is_single);
17878  arg5 = s2<se1?compile(++s2,se1,depth1,0,is_single):0;
17879  }
17880  }
17881  }
17882  _cimg_mp_check_type(arg2,2,1,0);
17883  _cimg_mp_check_type(arg3,3,1,0);
17884  _cimg_mp_check_type(arg4,4,1,0);
17885  _cimg_mp_check_type(arg5,5,1,0);
17886 
17887  c1 = *s1; *s1 = 0;
17888  variable_name.assign(CImg<charT>::string(ss8,true,true).unroll('y'),true);
17889  cimg::strpare(variable_name,false,true);
17890  if (_cimg_mp_is_vector(arg1))
17891  ((CImg<ulongT>::vector((ulongT)mp_vector_print,arg1,0,(ulongT)_cimg_mp_size(arg1),0),
17892  variable_name)>'y').move_to(opcode);
17893  else
17894  ((CImg<ulongT>::vector((ulongT)mp_print,arg1,0,0),
17895  variable_name)>'y').move_to(opcode);
17896  opcode[2] = opcode._height;
17897  opcode.move_to(code);
17898 
17899  ((CImg<ulongT>::vector((ulongT)mp_display,arg1,0,(ulongT)_cimg_mp_size(arg1),
17900  arg2,arg3,arg4,arg5),
17901  variable_name)>'y').move_to(opcode);
17902  opcode[2] = opcode._height;
17903  opcode.move_to(code);
17904  *s1 = c1;
17905  _cimg_mp_return(arg1);
17906 
17907  } else { // Image
17908  p1 = compile(ss8 + 1,se1,depth1,0,is_single);
17909  _cimg_mp_check_list(true);
17910  CImg<ulongT>::vector((ulongT)mp_image_display,_cimg_mp_slot_nan,p1).move_to(code);
17911  _cimg_mp_return_nan();
17912  }
17913  }
17914 
17915  if (!std::strncmp(ss,"det(",4)) { // Matrix determinant
17916  _cimg_mp_op("Function 'det()'");
17917  arg1 = compile(ss4,se1,depth1,0,is_single);
17918  _cimg_mp_check_matrix_square(arg1,1);
17919  p1 = (unsigned int)std::sqrt((float)_cimg_mp_size(arg1));
17920  _cimg_mp_scalar2(mp_det,arg1,p1);
17921  }
17922 
17923  if (!std::strncmp(ss,"diag(",5)) { // Diagonal matrix
17924  _cimg_mp_op("Function 'diag()'");
17925  arg1 = compile(ss5,se1,depth1,0,is_single);
17926  if (_cimg_mp_is_scalar(arg1)) _cimg_mp_return(arg1);
17927  p1 = _cimg_mp_size(arg1);
17928  pos = vector(p1*p1);
17929  CImg<ulongT>::vector((ulongT)mp_diag,pos,arg1,p1).move_to(code);
17930  _cimg_mp_return(pos);
17931  }
17932 
17933  if (!std::strncmp(ss,"dot(",4)) { // Dot product
17934  _cimg_mp_op("Function 'dot()'");
17935  s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
17936  arg1 = compile(ss4,s1,depth1,0,is_single);
17937  arg2 = compile(++s1,se1,depth1,0,is_single);
17938  _cimg_mp_check_type(arg1,1,2,0);
17939  _cimg_mp_check_type(arg2,2,2,0);
17940  if (_cimg_mp_is_vector(arg1)) _cimg_mp_scalar3(mp_dot,arg1,arg2,_cimg_mp_size(arg1));
17941  _cimg_mp_scalar2(mp_mul,arg1,arg2);
17942  }
17943 
17944  if (!std::strncmp(ss,"do(",3) || !std::strncmp(ss,"dowhile(",8)) { // Do..while
17945  _cimg_mp_op("Function 'dowhile()'");
17946  s0 = *ss2=='('?ss3:ss8;
17947  s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
17948  arg1 = code._width;
17949  arg6 = mempos;
17950  p1 = compile(s0,s1,depth1,0,is_single); // Body
17951  arg2 = code._width;
17952  p2 = s1<se1?compile(++s1,se1,depth1,0,is_single):p1; // Condition
17953  _cimg_mp_check_type(p2,2,1,0);
17954  CImg<ulongT>::vector((ulongT)mp_dowhile,p1,p2,arg2 - arg1,code._width - arg2,_cimg_mp_size(p1),
17955  p1>=arg6 && !_cimg_mp_is_constant(p1),
17956  p2>=arg6 && !_cimg_mp_is_constant(p2)).move_to(code,arg1);
17957  _cimg_mp_return(p1);
17958  }
17959 
17960  if (!std::strncmp(ss,"draw(",5)) { // Draw image
17961  if (!is_single) is_parallelizable = false;
17962  _cimg_mp_op("Function 'draw()'");
17963  if (*ss5=='#') { // Index specified
17964  s0 = ss6; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
17965  p1 = compile(ss6,s0++,depth1,0,is_single);
17966  _cimg_mp_check_list(true);
17967  } else { p1 = ~0U; s0 = ss5; }
17968  s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
17969  arg1 = compile(s0,s1,depth1,0,is_single);
17970  arg2 = is_relative?0U:(unsigned int)_cimg_mp_slot_x;
17971  arg3 = is_relative?0U:(unsigned int)_cimg_mp_slot_y;
17972  arg4 = is_relative?0U:(unsigned int)_cimg_mp_slot_z;
17973  arg5 = is_relative?0U:(unsigned int)_cimg_mp_slot_c;
17974  s0 = se1;
17975  if (s1<se1) {
17976  s0 = s1 + 1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
17977  arg2 = compile(++s1,s0,depth1,0,is_single);
17978  if (_cimg_mp_is_vector(arg2)) { // Coordinates specified as a vector
17979  p2 = _cimg_mp_size(arg2);
17980  ++arg2;
17981  if (p2>1) {
17982  arg3 = arg2 + 1;
17983  if (p2>2) {
17984  arg4 = arg3 + 1;
17985  if (p2>3) arg5 = arg4 + 1;
17986  }
17987  }
17988  ++s0;
17989  is_sth = true;
17990  } else {
17991  if (s0<se1) {
17992  is_sth = p1!=~0U;
17993  s1 = s0 + 1; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
17994  arg3 = compile(++s0,s1,depth1,0,is_single);
17995  _cimg_mp_check_type(arg3,is_sth?4:3,1,0);
17996  if (s1<se1) {
17997  s0 = s1 + 1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
17998  arg4 = compile(++s1,s0,depth1,0,is_single);
17999  _cimg_mp_check_type(arg4,is_sth?5:4,1,0);
18000  if (s0<se1) {
18001  s1 = s0 + 1; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18002  arg5 = compile(++s0,s1,depth1,0,is_single);
18003  _cimg_mp_check_type(arg5,is_sth?6:5,1,0);
18004  s0 = ++s1;
18005  }
18006  }
18007  }
18008  is_sth = false;
18009  }
18010  }
18011 
18012  CImg<ulongT>::vector((ulongT)mp_draw,arg1,(ulongT)_cimg_mp_size(arg1),p1,arg2,arg3,arg4,arg5,
18013  0,0,0,0,1,(ulongT)~0U,0,1).move_to(opcode);
18014 
18015  arg2 = arg3 = arg4 = arg5 = ~0U;
18016  p2 = p1!=~0U?0:1;
18017  if (s0<se1) {
18018  s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18019  arg2 = compile(s0,s1,depth1,0,is_single);
18020  _cimg_mp_check_type(arg2,p2 + (is_sth?3:6),1,0);
18021  if (s1<se1) {
18022  s0 = s1 + 1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
18023  arg3 = compile(++s1,s0,depth1,0,is_single);
18024  _cimg_mp_check_type(arg3,p2 + (is_sth?4:7),1,0);
18025  if (s0<se1) {
18026  s1 = s0 + 1; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18027  arg4 = compile(++s0,s1,depth1,0,is_single);
18028  _cimg_mp_check_type(arg4,p2 + (is_sth?5:8),1,0);
18029  if (s1<se1) {
18030  s0 = s1 + 1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
18031  arg5 = compile(++s1,s0,depth1,0,is_single);
18032  _cimg_mp_check_type(arg5,p2 + (is_sth?6:9),1,0);
18033  }
18034  }
18035  }
18036  }
18037  if (s0<s1) s0 = s1;
18038 
18039  opcode[8] = (ulongT)arg2;
18040  opcode[9] = (ulongT)arg3;
18041  opcode[10] = (ulongT)arg4;
18042  opcode[11] = (ulongT)arg5;
18043 
18044  if (s0<se1) {
18045  s1 = s0 + 1; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18046  arg6 = compile(++s0,s1,depth1,0,is_single);
18047  _cimg_mp_check_type(arg6,0,1,0);
18048  opcode[12] = arg6;
18049  if (s1<se1) {
18050  s0 = s1 + 1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
18051  p2 = compile(++s1,s0,depth1,0,is_single);
18052  _cimg_mp_check_type(p2,0,2,0);
18053  opcode[13] = p2;
18054  opcode[14] = _cimg_mp_size(p2);
18055  p3 = s0<se1?compile(++s0,se1,depth1,0,is_single):1;
18056  _cimg_mp_check_type(p3,0,1,0);
18057  opcode[15] = p3;
18058  }
18059  }
18060  opcode.move_to(code);
18061  _cimg_mp_return(arg1);
18062  }
18063 
18064  break;
18065 
18066  case 'e' :
18067  if (!std::strncmp(ss,"echo(",5)) { // Echo
18068  _cimg_mp_op("Function 'echo()'");
18069  CImg<ulongT>::vector((ulongT)mp_echo,_cimg_mp_slot_nan,0).move_to(_opcode);
18070  for (s = ss5; s<se; ++s) {
18071  ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
18072  (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
18073  arg1 = compile(s,ns,depth1,0,is_single);
18074  CImg<ulongT>::vector(arg1,_cimg_mp_size(arg1)).move_to(_opcode);
18075  s = ns;
18076  }
18077  (_opcode>'y').move_to(opcode);
18078  opcode[2] = opcode._height;
18079  opcode.move_to(code);
18080  _cimg_mp_return_nan();
18081  }
18082 
18083  if (!std::strncmp(ss,"eig(",4)) { // Matrix eigenvalues/eigenvector
18084  _cimg_mp_op("Function 'eig()'");
18085  arg1 = compile(ss4,se1,depth1,0,is_single);
18086  _cimg_mp_check_matrix_square(arg1,1);
18087  p1 = (unsigned int)std::sqrt((float)_cimg_mp_size(arg1));
18088  pos = vector((p1 + 1)*p1);
18089  CImg<ulongT>::vector((ulongT)mp_matrix_eig,pos,arg1,p1).move_to(code);
18090  _cimg_mp_return(pos);
18091  }
18092 
18093  if (!std::strncmp(ss,"end(",4)) { // End
18094  _cimg_mp_op("Function 'end()'");
18095  code.swap(code_end);
18096  compile(ss4,se1,depth1,p_ref,true);
18097  code.swap(code_end);
18098  _cimg_mp_return_nan();
18099  }
18100 
18101  if (!std::strncmp(ss,"ext(",4)) { // Extern
18102  _cimg_mp_op("Function 'ext()'");
18103  if (!is_single) is_parallelizable = false;
18104  CImg<ulongT>::vector((ulongT)mp_ext,0,0).move_to(_opcode);
18105  pos = 1;
18106  for (s = ss4; s<se; ++s) {
18107  ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
18108  (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
18109  arg1 = compile(s,ns,depth1,0,is_single);
18110  CImg<ulongT>::vector(arg1,_cimg_mp_size(arg1)).move_to(_opcode);
18111  s = ns;
18112  }
18113  (_opcode>'y').move_to(opcode);
18114  pos = scalar();
18115  opcode[1] = pos;
18116  opcode[2] = opcode._height;
18117  opcode.move_to(code);
18118  _cimg_mp_return(pos);
18119  }
18120 
18121  if (!std::strncmp(ss,"exp(",4)) { // Exponential
18122  _cimg_mp_op("Function 'exp()'");
18123  arg1 = compile(ss4,se1,depth1,0,is_single);
18124  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_exp,arg1);
18125  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::exp(mem[arg1]));
18126  _cimg_mp_scalar1(mp_exp,arg1);
18127  }
18128 
18129  if (!std::strncmp(ss,"eye(",4)) { // Identity matrix
18130  _cimg_mp_op("Function 'eye()'");
18131  arg1 = compile(ss4,se1,depth1,0,is_single);
18132  _cimg_mp_check_constant(arg1,1,3);
18133  p1 = (unsigned int)mem[arg1];
18134  pos = vector(p1*p1);
18135  CImg<ulongT>::vector((ulongT)mp_eye,pos,p1).move_to(code);
18136  _cimg_mp_return(pos);
18137  }
18138  break;
18139 
18140  case 'f' :
18141  if (!std::strncmp(ss,"fact(",5)) { // Factorial
18142  _cimg_mp_op("Function 'fact()'");
18143  arg1 = compile(ss5,se1,depth1,0,is_single);
18144  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_factorial,arg1);
18145  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::factorial(mem[arg1]));
18146  _cimg_mp_scalar1(mp_factorial,arg1);
18147  }
18148 
18149  if (!std::strncmp(ss,"fibo(",5)) { // Fibonacci
18150  _cimg_mp_op("Function 'fibo()'");
18151  arg1 = compile(ss5,se1,depth1,0,is_single);
18152  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_fibonacci,arg1);
18153  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::fibonacci(mem[arg1]));
18154  _cimg_mp_scalar1(mp_fibonacci,arg1);
18155  }
18156 
18157  if (!std::strncmp(ss,"find(",5)) { // Find
18158  _cimg_mp_op("Function 'find()'");
18159 
18160  // First argument: data to look at.
18161  s0 = ss5; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
18162  if (*ss5=='#') { // Index specified
18163  p1 = compile(ss6,s0,depth1,0,is_single);
18164  _cimg_mp_check_list(false);
18165  arg1 = ~0U;
18166  } else { // Vector specified
18167  arg1 = compile(ss5,s0,depth1,0,is_single);
18168  _cimg_mp_check_type(arg1,1,2,0);
18169  p1 = ~0U;
18170  }
18171 
18172  // Second argument: data to find.
18173  s1 = ++s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18174  arg2 = compile(s0,s1,depth1,0,is_single);
18175 
18176  // Third and fourth arguments: search direction and starting index.
18177  arg3 = 1; arg4 = _cimg_mp_slot_nan;
18178  if (s1<se1) {
18179  s0 = s1 + 1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
18180  arg3 = compile(++s1,s0,depth1,0,is_single);
18181  _cimg_mp_check_type(arg3,3,1,0);
18182  if (s0<se1) {
18183  arg4 = compile(++s0,se1,depth1,0,is_single);
18184  _cimg_mp_check_type(arg4,4,1,0);
18185  }
18186  }
18187  if (p1!=~0U) {
18188  if (_cimg_mp_is_vector(arg2))
18189  _cimg_mp_scalar5(mp_list_find_seq,p1,arg2,_cimg_mp_size(arg2),arg3,arg4);
18190  _cimg_mp_scalar4(mp_list_find,p1,arg2,arg3,arg4);
18191  }
18192  if (_cimg_mp_is_vector(arg2))
18193  _cimg_mp_scalar6(mp_find_seq,arg1,_cimg_mp_size(arg1),arg2,_cimg_mp_size(arg2),arg3,arg4);
18194  _cimg_mp_scalar5(mp_find,arg1,_cimg_mp_size(arg1),arg2,arg3,arg4);
18195  }
18196 
18197  if (*ss1=='o' && *ss2=='r' && *ss3=='(') { // For loop
18198  _cimg_mp_op("Function 'for()'");
18199  s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18200  s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
18201  s3 = s2 + 1; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
18202  arg1 = code._width;
18203  p1 = compile(ss4,s1,depth1,0,is_single); // Init
18204  arg2 = code._width;
18205  p2 = compile(++s1,s2,depth1,0,is_single); // Cond
18206  arg3 = code._width;
18207  arg6 = mempos;
18208  if (s3<se1) { // Body + post
18209  p3 = compile(s3 + 1,se1,depth1,0,is_single); // Body
18210  arg4 = code._width;
18211  pos = compile(++s2,s3,depth1,0,is_single); // Post
18212  } else {
18213  p3 = compile(++s2,se1,depth1,0,is_single); // Body only
18214  arg4 = pos = code._width;
18215  }
18216  _cimg_mp_check_type(p2,2,1,0);
18217  arg5 = _cimg_mp_size(pos);
18218  CImg<ulongT>::vector((ulongT)mp_for,p3,(ulongT)_cimg_mp_size(p3),p2,arg2 - arg1,arg3 - arg2,
18219  arg4 - arg3,code._width - arg4,
18220  p3>=arg6 && !_cimg_mp_is_constant(p3),
18221  p2>=arg6 && !_cimg_mp_is_constant(p2)).move_to(code,arg1);
18222  _cimg_mp_return(p3);
18223  }
18224 
18225  if (!std::strncmp(ss,"floor(",6)) { // Floor
18226  _cimg_mp_op("Function 'floor()'");
18227  arg1 = compile(ss6,se1,depth1,0,is_single);
18228  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_floor,arg1);
18229  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::floor(mem[arg1]));
18230  _cimg_mp_scalar1(mp_floor,arg1);
18231  }
18232 
18233  if (!std::strncmp(ss,"fsize(",6)) { // File size
18234  _cimg_mp_op("Function 'fsize()'");
18235  *se1 = 0;
18236  variable_name.assign(CImg<charT>::string(ss6,true,true).unroll('y'),true);
18237  cimg::strpare(variable_name,false,true);
18238  pos = scalar();
18239  ((CImg<ulongT>::vector((ulongT)mp_fsize,pos,0),variable_name)>'y').move_to(opcode);
18240  *se1 = ')';
18241  opcode[2] = opcode._height;
18242  opcode.move_to(code);
18243  _cimg_mp_return(pos);
18244  }
18245  break;
18246 
18247  case 'g' :
18248  if (!std::strncmp(ss,"gauss(",6)) { // Gaussian function
18249  _cimg_mp_op("Function 'gauss()'");
18250  s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18251  arg1 = compile(ss6,s1,depth1,0,is_single);
18252  arg2 = s1<se1?compile(++s1,se1,depth1,0,is_single):1;
18253  _cimg_mp_check_type(arg2,2,1,0);
18254  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector2_vs(mp_gauss,arg1,arg2);
18255  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) {
18256  val1 = mem[arg1];
18257  val2 = mem[arg2];
18258  _cimg_mp_constant(std::exp(-val1*val1/(2*val2*val2))/std::sqrt(2*val2*val2*cimg::PI));
18259  }
18260  _cimg_mp_scalar2(mp_gauss,arg1,arg2);
18261  }
18262 
18263  if (!std::strncmp(ss,"gcd(",4)) { // Gcd
18264  _cimg_mp_op("Function 'gcd()'");
18265  s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18266  arg1 = compile(ss4,s1,depth1,0,is_single);
18267  arg2 = compile(++s1,se1,depth1,0,is_single);
18268  _cimg_mp_check_type(arg1,1,1,0);
18269  _cimg_mp_check_type(arg2,2,1,0);
18270  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
18271  _cimg_mp_constant(cimg::gcd((long)mem[arg1],(long)mem[arg2]));
18272  _cimg_mp_scalar2(mp_gcd,arg1,arg2);
18273  }
18274  break;
18275 
18276  case 'h' :
18277  if (*ss1=='(') { // Image height
18278  _cimg_mp_op("Function 'h()'");
18279  if (*ss2=='#') { // Index specified
18280  p1 = compile(ss3,se1,depth1,0,is_single);
18281  _cimg_mp_check_list(false);
18282  } else { if (ss2!=se1) break; p1 = ~0U; }
18283  pos = scalar();
18284  CImg<ulongT>::vector((ulongT)mp_image_h,pos,p1).move_to(code);
18285  _cimg_mp_return(pos);
18286  }
18287  break;
18288 
18289  case 'i' :
18290  if (*ss1=='c' && *ss2=='(') { // Image median
18291  _cimg_mp_op("Function 'ic()'");
18292  if (*ss3=='#') { // Index specified
18293  p1 = compile(ss4,se1,depth1,0,is_single);
18294  _cimg_mp_check_list(false);
18295  } else { if (ss3!=se1) break; p1 = ~0U; }
18296  pos = scalar();
18297  CImg<ulongT>::vector((ulongT)mp_image_median,pos,p1).move_to(code);
18298  _cimg_mp_return(pos);
18299  }
18300 
18301  if (*ss1=='f' && *ss2=='(') { // If..then[..else.]
18302  _cimg_mp_op("Function 'if()'");
18303  s1 = ss3; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18304  s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
18305  arg1 = compile(ss3,s1,depth1,0,is_single);
18306  _cimg_mp_check_type(arg1,1,1,0);
18307  if (_cimg_mp_is_constant(arg1)) {
18308  if ((bool)mem[arg1]) return compile(++s1,s2,depth1,0,is_single);
18309  else return s2<se1?compile(++s2,se1,depth1,0,is_single):0;
18310  }
18311  p2 = code._width;
18312  arg2 = compile(++s1,s2,depth1,0,is_single);
18313  p3 = code._width;
18314  arg3 = s2<se1?compile(++s2,se1,depth1,0,is_single):
18315  _cimg_mp_is_vector(arg2)?vector(_cimg_mp_size(arg2),0):0;
18316  _cimg_mp_check_type(arg3,3,_cimg_mp_is_vector(arg2)?2:1,_cimg_mp_size(arg2));
18317  arg4 = _cimg_mp_size(arg2);
18318  if (arg4) pos = vector(arg4); else pos = scalar();
18319  CImg<ulongT>::vector((ulongT)mp_if,pos,arg1,arg2,arg3,
18320  p3 - p2,code._width - p3,arg4).move_to(code,p2);
18321  _cimg_mp_return(pos);
18322  }
18323 
18324  if (!std::strncmp(ss,"init(",5)) { // Init
18325  _cimg_mp_op("Function 'init()'");
18326  code.swap(code_init);
18327  arg1 = compile(ss5,se1,depth1,p_ref,true);
18328  code.swap(code_init);
18329  _cimg_mp_return(arg1);
18330  }
18331 
18332  if (!std::strncmp(ss,"int(",4)) { // Integer cast
18333  _cimg_mp_op("Function 'int()'");
18334  arg1 = compile(ss4,se1,depth1,0,is_single);
18335  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_int,arg1);
18336  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant((longT)mem[arg1]);
18337  _cimg_mp_scalar1(mp_int,arg1);
18338  }
18339 
18340  if (!std::strncmp(ss,"inv(",4)) { // Matrix/scalar inversion
18341  _cimg_mp_op("Function 'inv()'");
18342  arg1 = compile(ss4,se1,depth1,0,is_single);
18343  if (_cimg_mp_is_vector(arg1)) {
18344  _cimg_mp_check_matrix_square(arg1,1);
18345  p1 = (unsigned int)std::sqrt((float)_cimg_mp_size(arg1));
18346  pos = vector(p1*p1);
18347  CImg<ulongT>::vector((ulongT)mp_matrix_inv,pos,arg1,p1).move_to(code);
18348  _cimg_mp_return(pos);
18349  }
18350  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(1/mem[arg1]);
18351  _cimg_mp_scalar2(mp_div,1,arg1);
18352  }
18353 
18354  if (*ss1=='s') { // Family of 'is_?()' functions
18355 
18356  if (!std::strncmp(ss,"isbool(",7)) { // Is boolean?
18357  _cimg_mp_op("Function 'isbool()'");
18358  if (ss7==se1) _cimg_mp_return(0);
18359  arg1 = compile(ss7,se1,depth1,0,is_single);
18360  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isbool,arg1);
18361  if (_cimg_mp_is_constant(arg1)) _cimg_mp_return(mem[arg1]==0.0 || mem[arg1]==1.0);
18362  _cimg_mp_scalar1(mp_isbool,arg1);
18363  }
18364 
18365  if (!std::strncmp(ss,"isdir(",6)) { // Is directory?
18366  _cimg_mp_op("Function 'isdir()'");
18367  *se1 = 0;
18368  is_sth = cimg::is_directory(ss6);
18369  *se1 = ')';
18370  _cimg_mp_return(is_sth?1U:0U);
18371  }
18372 
18373  if (!std::strncmp(ss,"isfile(",7)) { // Is file?
18374  _cimg_mp_op("Function 'isfile()'");
18375  *se1 = 0;
18376  is_sth = cimg::is_file(ss7);
18377  *se1 = ')';
18378  _cimg_mp_return(is_sth?1U:0U);
18379  }
18380 
18381  if (!std::strncmp(ss,"isin(",5)) { // Is in sequence/vector?
18382  if (ss5>=se1) _cimg_mp_return(0);
18383  _cimg_mp_op("Function 'isin()'");
18384  pos = scalar();
18385  CImg<ulongT>::vector((ulongT)mp_isin,pos,0).move_to(_opcode);
18386  for (s = ss5; s<se; ++s) {
18387  ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
18388  (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
18389  arg1 = compile(s,ns,depth1,0,is_single);
18390  if (_cimg_mp_is_vector(arg1))
18391  CImg<ulongT>::sequence(_cimg_mp_size(arg1),arg1 + 1,
18392  arg1 + (ulongT)_cimg_mp_size(arg1)).
18393  move_to(_opcode);
18394  else CImg<ulongT>::vector(arg1).move_to(_opcode);
18395  s = ns;
18396  }
18397  (_opcode>'y').move_to(opcode);
18398  opcode[2] = opcode._height;
18399  opcode.move_to(code);
18400  _cimg_mp_return(pos);
18401  }
18402 
18403  if (!std::strncmp(ss,"isinf(",6)) { // Is infinite?
18404  _cimg_mp_op("Function 'isinf()'");
18405  if (ss6==se1) _cimg_mp_return(0);
18406  arg1 = compile(ss6,se1,depth1,0,is_single);
18407  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isinf,arg1);
18408  if (_cimg_mp_is_constant(arg1)) _cimg_mp_return((unsigned int)cimg::type<double>::is_inf(mem[arg1]));
18409  _cimg_mp_scalar1(mp_isinf,arg1);
18410  }
18411 
18412  if (!std::strncmp(ss,"isint(",6)) { // Is integer?
18413  _cimg_mp_op("Function 'isint()'");
18414  if (ss6==se1) _cimg_mp_return(0);
18415  arg1 = compile(ss6,se1,depth1,0,is_single);
18416  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isint,arg1);
18417  if (_cimg_mp_is_constant(arg1)) _cimg_mp_return((unsigned int)(cimg::mod(mem[arg1],1.0)==0));
18418  _cimg_mp_scalar1(mp_isint,arg1);
18419  }
18420 
18421  if (!std::strncmp(ss,"isnan(",6)) { // Is NaN?
18422  _cimg_mp_op("Function 'isnan()'");
18423  if (ss6==se1) _cimg_mp_return(0);
18424  arg1 = compile(ss6,se1,depth1,0,is_single);
18425  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isnan,arg1);
18426  if (_cimg_mp_is_constant(arg1)) _cimg_mp_return((unsigned int)cimg::type<double>::is_nan(mem[arg1]));
18427  _cimg_mp_scalar1(mp_isnan,arg1);
18428  }
18429 
18430  if (!std::strncmp(ss,"isval(",6)) { // Is value?
18431  _cimg_mp_op("Function 'isval()'");
18432  val = 0;
18433  if (cimg_sscanf(ss6,"%lf%c%c",&val,&sep,&end)==2 && sep==')') _cimg_mp_return(1);
18434  _cimg_mp_return(0);
18435  }
18436 
18437  }
18438  break;
18439 
18440  case 'l' :
18441  if (*ss1=='(') { // Size of image list
18442  _cimg_mp_op("Function 'l()'");
18443  if (ss2!=se1) break;
18444  _cimg_mp_scalar0(mp_list_l);
18445  }
18446 
18447  if (!std::strncmp(ss,"log(",4)) { // Natural logarithm
18448  _cimg_mp_op("Function 'log()'");
18449  arg1 = compile(ss4,se1,depth1,0,is_single);
18450  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log,arg1);
18451  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::log(mem[arg1]));
18452  _cimg_mp_scalar1(mp_log,arg1);
18453  }
18454 
18455  if (!std::strncmp(ss,"log2(",5)) { // Base-2 logarithm
18456  _cimg_mp_op("Function 'log2()'");
18457  arg1 = compile(ss5,se1,depth1,0,is_single);
18458  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log2,arg1);
18459  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::log2(mem[arg1]));
18460  _cimg_mp_scalar1(mp_log2,arg1);
18461  }
18462 
18463  if (!std::strncmp(ss,"log10(",6)) { // Base-10 logarithm
18464  _cimg_mp_op("Function 'log10()'");
18465  arg1 = compile(ss6,se1,depth1,0,is_single);
18466  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log10,arg1);
18467  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::log10(mem[arg1]));
18468  _cimg_mp_scalar1(mp_log10,arg1);
18469  }
18470 
18471  if (!std::strncmp(ss,"lowercase(",10)) { // Lower case
18472  _cimg_mp_op("Function 'lowercase()'");
18473  arg1 = compile(ss + 10,se1,depth1,0,is_single);
18474  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_lowercase,arg1);
18475  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::lowercase(mem[arg1]));
18476  _cimg_mp_scalar1(mp_lowercase,arg1);
18477  }
18478  break;
18479 
18480  case 'm' :
18481  if (!std::strncmp(ss,"mul(",4)) { // Matrix multiplication
18482  _cimg_mp_op("Function 'mul()'");
18483  s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18484  arg1 = compile(ss4,s1,depth1,0,is_single);
18485  s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
18486  arg2 = compile(++s1,s2,depth1,0,is_single);
18487  arg3 = s2<se1?compile(++s2,se1,depth1,0,is_single):1;
18488  _cimg_mp_check_type(arg1,1,2,0);
18489  _cimg_mp_check_type(arg2,2,2,0);
18490  _cimg_mp_check_constant(arg3,3,3);
18491  p1 = _cimg_mp_size(arg1);
18492  p2 = _cimg_mp_size(arg2);
18493  p3 = (unsigned int)mem[arg3];
18494  arg5 = p2/p3;
18495  arg4 = p1/arg5;
18496  if (arg4*arg5!=p1 || arg5*p3!=p2) {
18497  *se = saved_char;
18498  s0 = ss - 4>expr._data?ss - 4:expr._data;
18499  cimg::strellipsize(s0,64);
18500  throw CImgArgumentException("[" cimg_appname "_math_parser] "
18501  "CImg<%s>::%s: %s: Types of first and second arguments ('%s' and '%s') "
18502  "do not match with third argument 'nb_colsB=%u', "
18503  "in expression '%s%s%s'.",
18504  pixel_type(),_cimg_mp_calling_function,s_op,
18505  s_type(arg1)._data,s_type(arg2)._data,p3,
18506  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
18507  }
18508  pos = vector(arg4*p3);
18509  CImg<ulongT>::vector((ulongT)mp_matrix_mul,pos,arg1,arg2,arg4,arg5,p3).move_to(code);
18510  _cimg_mp_return(pos);
18511  }
18512  break;
18513 
18514  case 'n' :
18515  if (!std::strncmp(ss,"narg(",5)) { // Number of arguments
18516  _cimg_mp_op("Function 'narg()'");
18517  if (ss5>=se1) _cimg_mp_return(0);
18518  arg1 = 0;
18519  for (s = ss5; s<se; ++s) {
18520  ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
18521  (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
18522  ++arg1; s = ns;
18523  }
18524  _cimg_mp_constant(arg1);
18525  }
18526 
18527  if ((cimg_sscanf(ss,"norm%u%c",&(arg1=~0U),&sep)==2 && sep=='(') ||
18528  !std::strncmp(ss,"norminf(",8) || !std::strncmp(ss,"norm(",5) ||
18529  (!std::strncmp(ss,"norm",4) && ss5<se1 && (s=std::strchr(ss5,'('))!=0)) { // Lp norm
18530  _cimg_mp_op("Function 'normP()'");
18531  if (*ss4=='(') { arg1 = 2; s = ss5; }
18532  else if (*ss4=='i' && *ss5=='n' && *ss6=='f' && *ss7=='(') { arg1 = ~0U; s = ss8; }
18533  else if (arg1==~0U) {
18534  arg1 = compile(ss4,s++,depth1,0,is_single);
18535  _cimg_mp_check_constant(arg1,0,2);
18536  arg1 = (unsigned int)mem[arg1];
18537  } else s = std::strchr(ss4,'(') + 1;
18538  pos = scalar();
18539  switch (arg1) {
18540  case 0 :
18541  CImg<ulongT>::vector((ulongT)mp_norm0,pos,0).move_to(_opcode); break;
18542  case 1 :
18543  CImg<ulongT>::vector((ulongT)mp_norm1,pos,0).move_to(_opcode); break;
18544  case 2 :
18545  CImg<ulongT>::vector((ulongT)mp_norm2,pos,0).move_to(_opcode); break;
18546  case ~0U :
18547  CImg<ulongT>::vector((ulongT)mp_norminf,pos,0).move_to(_opcode); break;
18548  default :
18549  CImg<ulongT>::vector((ulongT)mp_normp,pos,0,(ulongT)(arg1==~0U?-1:(int)arg1)).
18550  move_to(_opcode);
18551  }
18552  for ( ; s<se; ++s) {
18553  ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
18554  (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
18555  arg2 = compile(s,ns,depth1,0,is_single);
18556  if (_cimg_mp_is_vector(arg2))
18557  CImg<ulongT>::sequence(_cimg_mp_size(arg2),arg2 + 1,
18558  arg2 + (ulongT)_cimg_mp_size(arg2)).
18559  move_to(_opcode);
18560  else CImg<ulongT>::vector(arg2).move_to(_opcode);
18561  s = ns;
18562  }
18563 
18564  (_opcode>'y').move_to(opcode);
18565  if (arg1>0 && opcode._height==4) // Special case with one argument and p>=1
18566  _cimg_mp_scalar1(mp_abs,opcode[3]);
18567  opcode[2] = opcode._height;
18568  opcode.move_to(code);
18569  _cimg_mp_return(pos);
18570  }
18571  break;
18572 
18573  case 'p' :
18574  if (!std::strncmp(ss,"permut(",7)) { // Number of permutations
18575  _cimg_mp_op("Function 'permut()'");
18576  s1 = ss7; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18577  s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
18578  arg1 = compile(ss7,s1,depth1,0,is_single);
18579  arg2 = compile(++s1,s2,depth1,0,is_single);
18580  arg3 = compile(++s2,se1,depth1,0,is_single);
18581  _cimg_mp_check_type(arg1,1,1,0);
18582  _cimg_mp_check_type(arg2,2,1,0);
18583  _cimg_mp_check_type(arg3,3,1,0);
18584  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2) && _cimg_mp_is_constant(arg3))
18585  _cimg_mp_constant(cimg::permutations(mem[arg1],mem[arg2],(bool)mem[arg3]));
18586  _cimg_mp_scalar3(mp_permutations,arg1,arg2,arg3);
18587  }
18588 
18589  if (!std::strncmp(ss,"pseudoinv(",10)) { // Matrix/scalar pseudo-inversion
18590  _cimg_mp_op("Function 'pseudoinv()'");
18591  s1 = ss + 10; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18592  arg1 = compile(ss + 10,s1,depth1,0,is_single);
18593  arg2 = s1<se1?compile(++s1,se1,depth1,0,is_single):1;
18594  _cimg_mp_check_type(arg1,1,2,0);
18595  _cimg_mp_check_constant(arg2,2,3);
18596  p1 = _cimg_mp_size(arg1);
18597  p2 = (unsigned int)mem[arg2];
18598  p3 = p1/p2;
18599  if (p3*p2!=p1) {
18600  *se = saved_char;
18601  s0 = ss - 4>expr._data?ss - 4:expr._data;
18602  cimg::strellipsize(s0,64);
18603  throw CImgArgumentException("[" cimg_appname "_math_parser] "
18604  "CImg<%s>::%s: %s: Type of first argument ('%s') "
18605  "does not match with second argument 'nb_colsA=%u', "
18606  "in expression '%s%s%s'.",
18607  pixel_type(),_cimg_mp_calling_function,s_op,
18608  s_type(arg1)._data,p2,
18609  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
18610  }
18611  pos = vector(p1);
18612  CImg<ulongT>::vector((ulongT)mp_matrix_pseudoinv,pos,arg1,p2,p3).move_to(code);
18613  _cimg_mp_return(pos);
18614  }
18615 
18616  if (!std::strncmp(ss,"print(",6) || !std::strncmp(ss,"prints(",7)) { // Print expressions
18617  is_sth = ss[5]=='s'; // is prints()
18618  _cimg_mp_op(is_sth?"Function 'prints()'":"Function 'print()'");
18619  s0 = is_sth?ss7:ss6;
18620  if (*s0!='#' || is_sth) { // Regular expression
18621  for (s = s0; s<se; ++s) {
18622  ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
18623  (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
18624  pos = compile(s,ns,depth1,p_ref,is_single);
18625  c1 = *ns; *ns = 0;
18626  variable_name.assign(CImg<charT>::string(s,true,true).unroll('y'),true);
18627  cimg::strpare(variable_name,false,true);
18628  if (_cimg_mp_is_vector(pos)) // Vector
18629  ((CImg<ulongT>::vector((ulongT)mp_vector_print,pos,0,(ulongT)_cimg_mp_size(pos),is_sth?1:0),
18630  variable_name)>'y').move_to(opcode);
18631  else // Scalar
18632  ((CImg<ulongT>::vector((ulongT)mp_print,pos,0,is_sth?1:0),
18633  variable_name)>'y').move_to(opcode);
18634  opcode[2] = opcode._height;
18635  opcode.move_to(code);
18636  *ns = c1; s = ns;
18637  }
18638  _cimg_mp_return(pos);
18639  } else { // Image
18640  p1 = compile(ss7,se1,depth1,0,is_single);
18641  _cimg_mp_check_list(true);
18642  CImg<ulongT>::vector((ulongT)mp_image_print,_cimg_mp_slot_nan,p1).move_to(code);
18643  _cimg_mp_return_nan();
18644  }
18645  }
18646  break;
18647 
18648  case 'r' :
18649  if (!std::strncmp(ss,"resize(",7)) { // Vector or image resize
18650  _cimg_mp_op("Function 'resize()'");
18651  if (*ss7!='#') { // Vector
18652  s1 = ss7; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18653  arg1 = compile(ss7,s1,depth1,0,is_single);
18654  s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
18655  arg2 = compile(s1,s2,depth1,0,is_single);
18656  arg3 = 1;
18657  arg4 = 0;
18658  if (s2<se1) {
18659  s1 = ++s2; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18660  arg3 = compile(s2,s1,depth1,0,is_single);
18661  arg4 = s1<se1?compile(++s1,se1,depth1,0,is_single):0;
18662  }
18663  _cimg_mp_check_constant(arg2,2,3);
18664  arg2 = (unsigned int)mem[arg2];
18665  _cimg_mp_check_type(arg3,3,1,0);
18666  _cimg_mp_check_type(arg4,4,1,0);
18667  pos = vector(arg2);
18668  CImg<ulongT>::vector((ulongT)mp_vector_resize,pos,arg2,arg1,(ulongT)_cimg_mp_size(arg1),
18669  arg3,arg4).move_to(code);
18670  _cimg_mp_return(pos);
18671 
18672  } else { // Image
18673  if (!is_single) is_parallelizable = false;
18674  s0 = ss8; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
18675  p1 = compile(ss8,s0++,depth1,0,is_single);
18676  _cimg_mp_check_list(true);
18677  CImg<ulongT>::vector((ulongT)mp_image_resize,_cimg_mp_slot_nan,p1,~0U,~0U,~0U,~0U,1,0,0,0,0,0).
18678  move_to(opcode);
18679  pos = 0;
18680  for (s = s0; s<se && pos<10; ++s) {
18681  ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
18682  (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
18683  arg1 = compile(s,ns,depth1,0,is_single);
18684  _cimg_mp_check_type(arg1,pos + 2,1,0);
18685  opcode[pos + 3] = arg1;
18686  s = ns;
18687  ++pos;
18688  }
18689  if (pos<1 || pos>10) {
18690  *se = saved_char;
18691  s0 = ss - 4>expr._data?ss - 4:expr._data;
18692  cimg::strellipsize(s0,64);
18693  throw CImgArgumentException("[" cimg_appname "_math_parser] "
18694  "CImg<%s>::%s: %s: %s arguments, in expression '%s%s%s'.",
18695  pixel_type(),_cimg_mp_calling_function,s_op,
18696  pos<1?"Missing":"Too much",
18697  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
18698  }
18699  opcode.move_to(code);
18700  _cimg_mp_return_nan();
18701  }
18702  }
18703 
18704  if (!std::strncmp(ss,"reverse(",8)) { // Vector reverse
18705  _cimg_mp_op("Function 'reverse()'");
18706  arg1 = compile(ss8,se1,depth1,0,is_single);
18707  if (!_cimg_mp_is_vector(arg1)) _cimg_mp_return(arg1);
18708  p1 = _cimg_mp_size(arg1);
18709  pos = vector(p1);
18710  CImg<ulongT>::vector((ulongT)mp_vector_reverse,pos,arg1,p1).move_to(code);
18711  _cimg_mp_return(pos);
18712  }
18713 
18714  if (!std::strncmp(ss,"rol(",4) || !std::strncmp(ss,"ror(",4)) { // Bitwise rotation
18715  _cimg_mp_op(ss[2]=='l'?"Function 'rol()'":"Function 'ror()'");
18716  s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1-expr._data]!=clevel1)) ++s1;
18717  arg1 = compile(ss4,s1,depth1,0,is_single);
18718  arg2 = s1<se1?compile(++s1,se1,depth1,0,is_single):1;
18719  _cimg_mp_check_type(arg2,2,1,0);
18720  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector2_vs(*ss2=='l'?mp_rol:mp_ror,arg1,arg2);
18721  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
18722  _cimg_mp_constant(*ss2=='l'?cimg::rol(mem[arg1],(unsigned int)mem[arg2]):
18723  cimg::ror(mem[arg1],(unsigned int)mem[arg2]));
18724  _cimg_mp_scalar2(*ss2=='l'?mp_rol:mp_ror,arg1,arg2);
18725  }
18726 
18727  if (!std::strncmp(ss,"rot(",4)) { // 2d/3d rotation matrix
18728  _cimg_mp_op("Function 'rot()'");
18729  s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18730  arg1 = compile(ss4,s1,depth1,0,is_single);
18731  if (s1<se1) { // 3d rotation
18732  _cimg_mp_check_type(arg1,1,3,3);
18733  is_sth = false; // Is coordinates as vector?
18734  if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector
18735  is_sth = true;
18736  p2 = _cimg_mp_size(arg1);
18737  ++arg1;
18738  arg2 = arg3 = 0;
18739  if (p2>1) {
18740  arg2 = arg1 + 1;
18741  if (p2>2) arg3 = arg2 + 1;
18742  }
18743  arg4 = compile(++s1,se1,depth1,0,is_single);
18744  } else {
18745  s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
18746  arg2 = compile(++s1,s2,depth1,0,is_single);
18747  s3 = s2 + 1; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
18748  arg3 = compile(++s2,s3,depth1,0,is_single);
18749  arg4 = compile(++s3,se1,depth1,0,is_single);
18750  _cimg_mp_check_type(arg2,2,1,0);
18751  _cimg_mp_check_type(arg3,3,1,0);
18752  }
18753  _cimg_mp_check_type(arg4,is_sth?2:4,1,0);
18754  pos = vector(9);
18755  CImg<ulongT>::vector((ulongT)mp_rot3d,pos,arg1,arg2,arg3,arg4).move_to(code);
18756  } else { // 2d rotation
18757  _cimg_mp_check_type(arg1,1,1,0);
18758  pos = vector(4);
18759  CImg<ulongT>::vector((ulongT)mp_rot2d,pos,arg1).move_to(code);
18760  }
18761  _cimg_mp_return(pos);
18762  }
18763 
18764  if (!std::strncmp(ss,"round(",6)) { // Value rounding
18765  _cimg_mp_op("Function 'round()'");
18766  s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18767  arg1 = compile(ss6,s1,depth1,0,is_single);
18768  arg2 = 1;
18769  arg3 = 0;
18770  if (s1<se1) {
18771  s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
18772  arg2 = compile(++s1,s2,depth1,0,is_single);
18773  arg3 = s2<se1?compile(++s2,se1,depth1,0,is_single):0;
18774  }
18775  _cimg_mp_check_type(arg2,2,1,0);
18776  _cimg_mp_check_type(arg3,3,1,0);
18777  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector3_vss(mp_round,arg1,arg2,arg3);
18778  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2) && _cimg_mp_is_constant(arg3))
18779  _cimg_mp_constant(cimg::round(mem[arg1],mem[arg2],(int)mem[arg3]));
18780  _cimg_mp_scalar3(mp_round,arg1,arg2,arg3);
18781  }
18782  break;
18783 
18784  case 's' :
18785  if (*ss1=='(') { // Image spectrum
18786  _cimg_mp_op("Function 's()'");
18787  if (*ss2=='#') { // Index specified
18788  p1 = compile(ss3,se1,depth1,0,is_single);
18789  _cimg_mp_check_list(false);
18790  } else { if (ss2!=se1) break; p1 = ~0U; }
18791  pos = scalar();
18792  CImg<ulongT>::vector((ulongT)mp_image_s,pos,p1).move_to(code);
18793  _cimg_mp_return(pos);
18794  }
18795 
18796  if (!std::strncmp(ss,"same(",5)) { // Test if operands have the same values
18797  _cimg_mp_op("Function 'same()'");
18798  s1 = ss5; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18799  arg1 = compile(ss5,s1,depth1,0,is_single);
18800  s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
18801  arg2 = compile(++s1,s2,depth1,0,is_single);
18802  arg3 = 11;
18803  arg4 = 1;
18804  if (s2<se1) {
18805  s3 = s2 + 1; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
18806  arg3 = compile(++s2,s3,depth1,0,is_single);
18807  _cimg_mp_check_type(arg3,3,1,0);
18808  arg4 = s3<se1?compile(++s3,se1,depth1,0,is_single):1;
18809  }
18810  p1 = _cimg_mp_size(arg1);
18811  p2 = _cimg_mp_size(arg2);
18812  _cimg_mp_scalar6(mp_vector_eq,arg1,p1,arg2,p2,arg3,arg4);
18813  }
18814 
18815  if (!std::strncmp(ss,"shift(",6)) { // Shift vector
18816  _cimg_mp_op("Function 'shift()'");
18817  s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18818  arg1 = compile(ss6,s1,depth1,0,is_single);
18819  arg2 = 1; arg3 = 0;
18820  if (s1<se1) {
18821  s0 = ++s1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
18822  arg2 = compile(s1,s0,depth1,0,is_single);
18823  arg3 = s0<se1?compile(++s0,se1,depth1,0,is_single):0;
18824  }
18825  _cimg_mp_check_type(arg1,1,2,0);
18826  _cimg_mp_check_type(arg2,2,1,0);
18827  _cimg_mp_check_type(arg3,3,1,0);
18828  p1 = _cimg_mp_size(arg1);
18829  pos = vector(p1);
18830  CImg<ulongT>::vector((ulongT)mp_shift,pos,arg1,p1,arg2,arg3).move_to(code);
18831  _cimg_mp_return(pos);
18832  }
18833 
18834  if (!std::strncmp(ss,"sign(",5)) { // Sign
18835  _cimg_mp_op("Function 'sign()'");
18836  arg1 = compile(ss5,se1,depth1,0,is_single);
18837  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sign,arg1);
18838  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::sign(mem[arg1]));
18839  _cimg_mp_scalar1(mp_sign,arg1);
18840  }
18841 
18842  if (!std::strncmp(ss,"sin(",4)) { // Sine
18843  _cimg_mp_op("Function 'sin()'");
18844  arg1 = compile(ss4,se1,depth1,0,is_single);
18845  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sin,arg1);
18846  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::sin(mem[arg1]));
18847  _cimg_mp_scalar1(mp_sin,arg1);
18848  }
18849 
18850  if (!std::strncmp(ss,"sinc(",5)) { // Sine cardinal
18851  _cimg_mp_op("Function 'sinc()'");
18852  arg1 = compile(ss5,se1,depth1,0,is_single);
18853  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sinc,arg1);
18854  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::sinc(mem[arg1]));
18855  _cimg_mp_scalar1(mp_sinc,arg1);
18856  }
18857 
18858  if (!std::strncmp(ss,"sinh(",5)) { // Hyperbolic sine
18859  _cimg_mp_op("Function 'sinh()'");
18860  arg1 = compile(ss5,se1,depth1,0,is_single);
18861  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sinh,arg1);
18862  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::sinh(mem[arg1]));
18863  _cimg_mp_scalar1(mp_sinh,arg1);
18864  }
18865 
18866  if (!std::strncmp(ss,"size(",5)) { // Vector size.
18867  _cimg_mp_op("Function 'size()'");
18868  arg1 = compile(ss5,se1,depth1,0,is_single);
18869  _cimg_mp_constant(_cimg_mp_is_scalar(arg1)?0:_cimg_mp_size(arg1));
18870  }
18871 
18872  if (!std::strncmp(ss,"solve(",6)) { // Solve linear system
18873  _cimg_mp_op("Function 'solve()'");
18874  s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18875  arg1 = compile(ss6,s1,depth1,0,is_single);
18876  s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
18877  arg2 = compile(++s1,s2,depth1,0,is_single);
18878  arg3 = s2<se1?compile(++s2,se1,depth1,0,is_single):1;
18879  _cimg_mp_check_type(arg1,1,2,0);
18880  _cimg_mp_check_type(arg2,2,2,0);
18881  _cimg_mp_check_constant(arg3,3,3);
18882  p1 = _cimg_mp_size(arg1);
18883  p2 = _cimg_mp_size(arg2);
18884  p3 = (unsigned int)mem[arg3];
18885  arg5 = p2/p3;
18886  arg4 = p1/arg5;
18887  if (arg4*arg5!=p1 || arg5*p3!=p2) {
18888  *se = saved_char;
18889  s0 = ss - 4>expr._data?ss - 4:expr._data;
18890  cimg::strellipsize(s0,64);
18891  throw CImgArgumentException("[" cimg_appname "_math_parser] "
18892  "CImg<%s>::%s: %s: Types of first and second arguments ('%s' and '%s') "
18893  "do not match with third argument 'nb_colsB=%u', "
18894  "in expression '%s%s%s'.",
18895  pixel_type(),_cimg_mp_calling_function,s_op,
18896  s_type(arg1)._data,s_type(arg2)._data,p3,
18897  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
18898  }
18899  pos = vector(arg4*p3);
18900  CImg<ulongT>::vector((ulongT)mp_solve,pos,arg1,arg2,arg4,arg5,p3).move_to(code);
18901  _cimg_mp_return(pos);
18902  }
18903 
18904  if (!std::strncmp(ss,"sort(",5)) { // Sort vector
18905  _cimg_mp_op("Function 'sort()'");
18906  if (*ss5!='#') { // Vector
18907  s1 = ss5; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18908  arg1 = compile(ss5,s1,depth1,0,is_single);
18909  arg2 = arg3 = 1;
18910  if (s1<se1) {
18911  s0 = ++s1; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
18912  arg2 = compile(s1,s0,depth1,0,is_single);
18913  arg3 = s0<se1?compile(++s0,se1,depth1,0,is_single):1;
18914  }
18915  _cimg_mp_check_type(arg1,1,2,0);
18916  _cimg_mp_check_type(arg2,2,1,0);
18917  _cimg_mp_check_constant(arg3,3,3);
18918  arg3 = (unsigned int)mem[arg3];
18919  p1 = _cimg_mp_size(arg1);
18920  if (p1%arg3) {
18921  *se = saved_char;
18922  s0 = ss - 4>expr._data?ss - 4:expr._data;
18923  cimg::strellipsize(s0,64);
18924  throw CImgArgumentException("[" cimg_appname "_math_parser] "
18925  "CImg<%s>::%s: %s: Invalid specified chunk size (%u) for first argument "
18926  "('%s'), in expression '%s%s%s'.",
18927  pixel_type(),_cimg_mp_calling_function,s_op,
18928  arg3,s_type(arg1)._data,
18929  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
18930  }
18931  pos = vector(p1);
18932  CImg<ulongT>::vector((ulongT)mp_sort,pos,arg1,p1,arg2,arg3).move_to(code);
18933  _cimg_mp_return(pos);
18934 
18935  } else { // Image
18936  s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18937  p1 = compile(ss6,s1,depth1,0,is_single);
18938  arg1 = 1;
18939  arg2 = constant(-1.0);
18940  if (s1<se1) {
18941  s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
18942  arg1 = compile(++s1,s2,depth1,0,is_single);
18943  if (s2<se1) arg2 = compile(++s2,se1,depth1,0,is_single);
18944  }
18945  _cimg_mp_check_type(arg1,2,1,0);
18946  _cimg_mp_check_type(arg2,3,1,0);
18947  _cimg_mp_check_list(true);
18948  CImg<ulongT>::vector((ulongT)mp_image_sort,_cimg_mp_slot_nan,p1,arg1,arg2).move_to(code);
18949  _cimg_mp_return_nan();
18950  }
18951  }
18952 
18953  if (!std::strncmp(ss,"sqr(",4)) { // Square
18954  _cimg_mp_op("Function 'sqr()'");
18955  arg1 = compile(ss4,se1,depth1,0,is_single);
18956  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sqr,arg1);
18957  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::sqr(mem[arg1]));
18958  _cimg_mp_scalar1(mp_sqr,arg1);
18959  }
18960 
18961  if (!std::strncmp(ss,"sqrt(",5)) { // Square root
18962  _cimg_mp_op("Function 'sqrt()'");
18963  arg1 = compile(ss5,se1,depth1,0,is_single);
18964  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sqrt,arg1);
18965  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::sqrt(mem[arg1]));
18966  _cimg_mp_scalar1(mp_sqrt,arg1);
18967  }
18968 
18969  if (!std::strncmp(ss,"srand(",6)) { // Set RNG seed
18970  _cimg_mp_op("Function 'srand()'");
18971  arg1 = ss6<se1?compile(ss6,se1,depth1,0,is_single):~0U;
18972  if (arg1!=~0U) { _cimg_mp_check_type(arg1,1,1,0); _cimg_mp_scalar1(mp_srand,arg1); }
18973  _cimg_mp_scalar0(mp_srand0);
18974  }
18975 
18976  if (!std::strncmp(ss,"stats(",6)) { // Image statistics
18977  _cimg_mp_op("Function 'stats()'");
18978  if (*ss6=='#') { // Index specified
18979  p1 = compile(ss7,se1,depth1,0,is_single);
18980  _cimg_mp_check_list(false);
18981  } else { if (ss6!=se1) break; p1 = ~0U; }
18982  pos = vector(14);
18983  CImg<ulongT>::vector((ulongT)mp_image_stats,pos,p1).move_to(code);
18984  _cimg_mp_return(pos);
18985  }
18986 
18987  if (!std::strncmp(ss,"stov(",5)) { // String to double
18988  _cimg_mp_op("Function 'stov()'");
18989  s1 = ss5; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
18990  arg1 = compile(ss5,s1,depth1,0,is_single);
18991  arg2 = arg3 = 0;
18992  if (s1<se1) {
18993  s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
18994  arg2 = compile(++s1,s2,depth1,0,is_single);
18995  arg3 = s2<se1?compile(++s2,se1,depth1,0,is_single):0;
18996  }
18997  _cimg_mp_check_type(arg2,2,1,0);
18998  _cimg_mp_check_type(arg3,3,1,0);
18999  p1 = _cimg_mp_size(arg1);
19000  _cimg_mp_scalar4(mp_stov,arg1,p1,arg2,arg3);
19001  }
19002 
19003  if (!std::strncmp(ss,"svd(",4)) { // Matrix SVD
19004  _cimg_mp_op("Function 'svd()'");
19005  s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
19006  arg1 = compile(ss4,s1,depth1,0,is_single);
19007  arg2 = s1<se1?compile(++s1,se1,depth1,0,is_single):1;
19008  _cimg_mp_check_type(arg1,1,2,0);
19009  _cimg_mp_check_constant(arg2,2,3);
19010  p1 = _cimg_mp_size(arg1);
19011  p2 = (unsigned int)mem[arg2];
19012  p3 = p1/p2;
19013  if (p3*p2!=p1) {
19014  *se = saved_char;
19015  s0 = ss - 4>expr._data?ss - 4:expr._data;
19016  cimg::strellipsize(s0,64);
19017  throw CImgArgumentException("[" cimg_appname "_math_parser] "
19018  "CImg<%s>::%s: %s: Type of first argument ('%s') "
19019  "does not match with second argument 'nb_colsA=%u', "
19020  "in expression '%s%s%s'.",
19021  pixel_type(),_cimg_mp_calling_function,s_op,
19022  s_type(arg1)._data,p2,
19023  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
19024  }
19025  pos = vector(p1 + p2 + p2*p2);
19026  CImg<ulongT>::vector((ulongT)mp_matrix_svd,pos,arg1,p2,p3).move_to(code);
19027  _cimg_mp_return(pos);
19028  }
19029  break;
19030 
19031  case 't' :
19032  if (!std::strncmp(ss,"tan(",4)) { // Tangent
19033  _cimg_mp_op("Function 'tan()'");
19034  arg1 = compile(ss4,se1,depth1,0,is_single);
19035  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_tan,arg1);
19036  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::tan(mem[arg1]));
19037  _cimg_mp_scalar1(mp_tan,arg1);
19038  }
19039 
19040  if (!std::strncmp(ss,"tanh(",5)) { // Hyperbolic tangent
19041  _cimg_mp_op("Function 'tanh()'");
19042  arg1 = compile(ss5,se1,depth1,0,is_single);
19043  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_tanh,arg1);
19044  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::tanh(mem[arg1]));
19045  _cimg_mp_scalar1(mp_tanh,arg1);
19046  }
19047 
19048  if (!std::strncmp(ss,"trace(",6)) { // Matrix trace
19049  _cimg_mp_op("Function 'trace()'");
19050  arg1 = compile(ss6,se1,depth1,0,is_single);
19051  _cimg_mp_check_matrix_square(arg1,1);
19052  p1 = (unsigned int)std::sqrt((float)_cimg_mp_size(arg1));
19053  _cimg_mp_scalar2(mp_trace,arg1,p1);
19054  }
19055 
19056  if (!std::strncmp(ss,"transp(",7)) { // Matrix transpose
19057  _cimg_mp_op("Function 'transp()'");
19058  s1 = ss7; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
19059  arg1 = compile(ss7,s1,depth1,0,is_single);
19060  arg2 = compile(++s1,se1,depth1,0,is_single);
19061  _cimg_mp_check_type(arg1,1,2,0);
19062  _cimg_mp_check_constant(arg2,2,3);
19063  p1 = _cimg_mp_size(arg1);
19064  p2 = (unsigned int)mem[arg2];
19065  p3 = p1/p2;
19066  if (p2*p3!=p1) {
19067  *se = saved_char;
19068  s0 = ss - 4>expr._data?ss - 4:expr._data;
19069  cimg::strellipsize(s0,64);
19070  throw CImgArgumentException("[" cimg_appname "_math_parser] "
19071  "CImg<%s>::%s: %s: Size of first argument ('%s') does not match "
19072  "second argument 'nb_cols=%u', in expression '%s%s%s'.",
19073  pixel_type(),_cimg_mp_calling_function,s_op,
19074  s_type(arg1)._data,p2,
19075  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
19076  }
19077  pos = vector(p3*p2);
19078  CImg<ulongT>::vector((ulongT)mp_transp,pos,arg1,p2,p3).move_to(code);
19079  _cimg_mp_return(pos);
19080  }
19081  break;
19082 
19083  case 'u' :
19084  if (*ss1=='(') { // Random value with uniform distribution
19085  _cimg_mp_op("Function 'u()'");
19086  if (*ss2==')') _cimg_mp_scalar2(mp_u,0,1);
19087  s1 = ss2; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
19088  arg1 = compile(ss2,s1,depth1,0,is_single);
19089  if (s1<se1) arg2 = compile(++s1,se1,depth1,0,is_single); else { arg2 = arg1; arg1 = 0; }
19090  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
19091  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_u,arg1,arg2);
19092  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_u,arg1,arg2);
19093  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_u,arg1,arg2);
19094  _cimg_mp_scalar2(mp_u,arg1,arg2);
19095  }
19096 
19097  if (!std::strncmp(ss,"unref(",6)) { // Un-reference variable
19098  _cimg_mp_op("Function 'unref()'");
19099  arg1 = ~0U;
19100  for (s0 = ss6; s0<se1; s0 = s1) {
19101  if (s0>ss6 && *s0==',') ++s0;
19102  s1 = s0; while (s1<se1 && *s1!=',') ++s1;
19103  c1 = *s1;
19104  if (s1>s0) {
19105  *s1 = 0;
19106  arg2 = arg3 = ~0U;
19107  if (s0[0]=='w' && s0[1]=='h' && !s0[2]) arg1 = reserved_label[arg3 = 0];
19108  else if (s0[0]=='w' && s0[1]=='h' && s0[2]=='d' && !s0[3]) arg1 = reserved_label[arg3 = 1];
19109  else if (s0[0]=='w' && s0[1]=='h' && s0[2]=='d' && s0[3]=='s' && !s0[4])
19110  arg1 = reserved_label[arg3 = 2];
19111  else if (s0[0]=='p' && s0[1]=='i' && !s0[2]) arg1 = reserved_label[arg3 = 3];
19112  else if (s0[0]=='i' && s0[1]=='m' && !s0[2]) arg1 = reserved_label[arg3 = 4];
19113  else if (s0[0]=='i' && s0[1]=='M' && !s0[2]) arg1 = reserved_label[arg3 = 5];
19114  else if (s0[0]=='i' && s0[1]=='a' && !s0[2]) arg1 = reserved_label[arg3 = 6];
19115  else if (s0[0]=='i' && s0[1]=='v' && !s0[2]) arg1 = reserved_label[arg3 = 7];
19116  else if (s0[0]=='i' && s0[1]=='s' && !s0[2]) arg1 = reserved_label[arg3 = 8];
19117  else if (s0[0]=='i' && s0[1]=='p' && !s0[2]) arg1 = reserved_label[arg3 = 9];
19118  else if (s0[0]=='i' && s0[1]=='c' && !s0[2]) arg1 = reserved_label[arg3 = 10];
19119  else if (s0[0]=='x' && s0[1]=='m' && !s0[2]) arg1 = reserved_label[arg3 = 11];
19120  else if (s0[0]=='y' && s0[1]=='m' && !s0[2]) arg1 = reserved_label[arg3 = 12];
19121  else if (s0[0]=='z' && s0[1]=='m' && !s0[2]) arg1 = reserved_label[arg3 = 13];
19122  else if (s0[0]=='c' && s0[1]=='m' && !s0[2]) arg1 = reserved_label[arg3 = 14];
19123  else if (s0[0]=='x' && s0[1]=='M' && !s0[2]) arg1 = reserved_label[arg3 = 15];
19124  else if (s0[0]=='y' && s0[1]=='M' && !s0[2]) arg1 = reserved_label[arg3 = 16];
19125  else if (s0[0]=='z' && s0[1]=='M' && !s0[2]) arg1 = reserved_label[arg3 = 17];
19126  else if (s0[0]=='c' && s0[1]=='M' && !s0[2]) arg1 = reserved_label[arg3 = 18];
19127  else if (s0[0]=='i' && s0[1]>='0' && s0[1]<='9' && !s0[2])
19128  arg1 = reserved_label[arg3 = 19 + s0[1] - '0'];
19129  else if (!std::strcmp(s0,"interpolation")) arg1 = reserved_label[arg3 = 29];
19130  else if (!std::strcmp(s0,"boundary")) arg1 = reserved_label[arg3 = 30];
19131  else if (s0[1]) { // Multi-char variable
19132  cimglist_for(variable_def,i) if (!std::strcmp(s0,variable_def[i])) {
19133  arg1 = variable_pos[i]; arg2 = i; break;
19134  }
19135  } else arg1 = reserved_label[arg3 = *s0]; // Single-char variable
19136 
19137  if (arg1!=~0U) {
19138  if (arg2==~0U) { if (arg3!=~0U) reserved_label[arg3] = ~0U; }
19139  else {
19140  variable_def.remove(arg2);
19141  if (arg2<variable_pos._width - 1)
19142  std::memmove(variable_pos._data + arg2,variable_pos._data + arg2 + 1,
19143  sizeof(uintT)*(variable_pos._width - arg2 - 1));
19144  --variable_pos._width;
19145  }
19146  }
19147  *s1 = c1;
19148  } else compile(s0,s1,depth1,0,is_single); // Will throw a 'missing argument' exception
19149  }
19150  _cimg_mp_return(arg1!=~0U?arg1:_cimg_mp_slot_nan); // Return value of last specified variable.
19151  }
19152 
19153  if (!std::strncmp(ss,"uppercase(",10)) { // Upper case
19154  _cimg_mp_op("Function 'uppercase()'");
19155  arg1 = compile(ss + 10,se1,depth1,0,is_single);
19156  if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_uppercase,arg1);
19157  if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::uppercase(mem[arg1]));
19158  _cimg_mp_scalar1(mp_uppercase,arg1);
19159  }
19160  break;
19161 
19162  case 'v' :
19163  if ((cimg_sscanf(ss,"vector%u%c",&(arg1=~0U),&sep)==2 && sep=='(' && arg1>0) ||
19164  !std::strncmp(ss,"vector(",7) ||
19165  (!std::strncmp(ss,"vector",6) && ss7<se1 && (s=std::strchr(ss7,'('))!=0)) { // Vector
19166  _cimg_mp_op("Function 'vector()'");
19167  arg2 = 0; // Number of specified values.
19168  if (arg1==~0U && *ss6!='(') {
19169  arg1 = compile(ss6,s++,depth1,0,is_single);
19170  _cimg_mp_check_constant(arg1,0,3);
19171  arg1 = (unsigned int)mem[arg1];
19172  } else s = std::strchr(ss6,'(') + 1;
19173 
19174  if (s<se1 || arg1==~0U) for ( ; s<se; ++s) {
19175  ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
19176  (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
19177  arg3 = compile(s,ns,depth1,0,is_single);
19178  if (_cimg_mp_is_vector(arg3)) {
19179  arg4 = _cimg_mp_size(arg3);
19180  CImg<ulongT>::sequence(arg4,arg3 + 1,arg3 + arg4).move_to(_opcode);
19181  arg2+=arg4;
19182  } else { CImg<ulongT>::vector(arg3).move_to(_opcode); ++arg2; }
19183  s = ns;
19184  }
19185  if (arg1==~0U) arg1 = arg2;
19186  _cimg_mp_check_vector0(arg1);
19187  pos = vector(arg1);
19188  _opcode.insert(CImg<ulongT>::vector((ulongT)mp_vector_init,pos,0,arg1),0);
19189  (_opcode>'y').move_to(opcode);
19190  opcode[2] = opcode._height;
19191  opcode.move_to(code);
19192  _cimg_mp_return(pos);
19193  }
19194 
19195  if (!std::strncmp(ss,"vtos(",5)) { // Double(s) to string
19196  _cimg_mp_op("Function 'vtos()'");
19197  s1 = ss5; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
19198  arg1 = compile(ss5,s1,depth1,0,is_single);
19199  arg2 = 0; arg3 = ~0U;
19200  if (s1<se1) {
19201  s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
19202  arg2 = compile(++s1,s2,depth1,0,is_single);
19203  arg3 = s2<se1?compile(++s2,se1,depth1,0,is_single):~0U;
19204  }
19205  _cimg_mp_check_type(arg2,2,1,0);
19206  if (arg3==~0U) { // Auto-guess best output vector size
19207  p1 = _cimg_mp_size(arg1);
19208  p1 = p1?19*p1 - 1:18;
19209  } else {
19210  _cimg_mp_check_constant(arg3,3,3);
19211  p1 = (unsigned int)mem[arg3];
19212  }
19213  pos = vector(p1);
19214  CImg<ulongT>::vector((ulongT)mp_vtos,pos,p1,arg1,_cimg_mp_size(arg1),arg2).move_to(code);
19215  _cimg_mp_return(pos);
19216  }
19217  break;
19218 
19219  case 'w' :
19220  if (*ss1=='(') { // Image width
19221  _cimg_mp_op("Function 'w()'");
19222  if (*ss2=='#') { // Index specified
19223  p1 = compile(ss3,se1,depth1,0,is_single);
19224  _cimg_mp_check_list(false);
19225  } else { if (ss2!=se1) break; p1 = ~0U; }
19226  pos = scalar();
19227  CImg<ulongT>::vector((ulongT)mp_image_w,pos,p1).move_to(code);
19228  _cimg_mp_return(pos);
19229  }
19230 
19231  if (*ss1=='h' && *ss2=='(') { // Image width*height
19232  _cimg_mp_op("Function 'wh()'");
19233  if (*ss3=='#') { // Index specified
19234  p1 = compile(ss4,se1,depth1,0,is_single);
19235  _cimg_mp_check_list(false);
19236  } else { if (ss3!=se1) break; p1 = ~0U; }
19237  pos = scalar();
19238  CImg<ulongT>::vector((ulongT)mp_image_wh,pos,p1).move_to(code);
19239  _cimg_mp_return(pos);
19240  }
19241 
19242  if (*ss1=='h' && *ss2=='d' && *ss3=='(') { // Image width*height*depth
19243  _cimg_mp_op("Function 'whd()'");
19244  if (*ss4=='#') { // Index specified
19245  p1 = compile(ss5,se1,depth1,0,is_single);
19246  _cimg_mp_check_list(false);
19247  } else { if (ss4!=se1) break; p1 = ~0U; }
19248  pos = scalar();
19249  CImg<ulongT>::vector((ulongT)mp_image_whd,pos,p1).move_to(code);
19250  _cimg_mp_return(pos);
19251  }
19252 
19253  if (*ss1=='h' && *ss2=='d' && *ss3=='s' && *ss4=='(') { // Image width*height*depth*spectrum
19254  _cimg_mp_op("Function 'whds()'");
19255  if (*ss5=='#') { // Index specified
19256  p1 = compile(ss6,se1,depth1,0,is_single);
19257  _cimg_mp_check_list(false);
19258  } else { if (ss5!=se1) break; p1 = ~0U; }
19259  pos = scalar();
19260  CImg<ulongT>::vector((ulongT)mp_image_whds,pos,p1).move_to(code);
19261  _cimg_mp_return(pos);
19262  }
19263 
19264  if (!std::strncmp(ss,"while(",6) || !std::strncmp(ss,"whiledo(",8)) { // While...do
19265  _cimg_mp_op("Function 'whiledo()'");
19266  s0 = *ss5=='('?ss6:ss8;
19267  s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
19268  p1 = code._width;
19269  arg1 = compile(s0,s1,depth1,0,is_single);
19270  p2 = code._width;
19271  arg6 = mempos;
19272  pos = compile(++s1,se1,depth1,0,is_single);
19273  _cimg_mp_check_type(arg1,1,1,0);
19274  arg2 = _cimg_mp_size(pos);
19275  CImg<ulongT>::vector((ulongT)mp_whiledo,pos,arg1,p2 - p1,code._width - p2,arg2,
19276  pos>=arg6 && !_cimg_mp_is_constant(pos),
19277  arg1>=arg6 && !_cimg_mp_is_constant(arg1)).move_to(code,p1);
19278  _cimg_mp_return(pos);
19279  }
19280  break;
19281 
19282  case 'x' :
19283  if (!std::strncmp(ss,"xor(",4)) { // Xor
19284  _cimg_mp_op("Function 'xor()'");
19285  s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
19286  arg1 = compile(ss4,s1,depth1,0,is_single);
19287  arg2 = compile(++s1,se1,depth1,0,is_single);
19288  _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1));
19289  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_bitwise_xor,arg1,arg2);
19290  if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_bitwise_xor,arg1,arg2);
19291  if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_bitwise_xor,arg1,arg2);
19292  if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
19293  _cimg_mp_constant((longT)mem[arg1] ^ (longT)mem[arg2]);
19294  _cimg_mp_scalar2(mp_bitwise_xor,arg1,arg2);
19295  }
19296  break;
19297  }
19298 
19299  if (!std::strncmp(ss,"min(",4) || !std::strncmp(ss,"max(",4) ||
19300  !std::strncmp(ss,"med(",4) || !std::strncmp(ss,"kth(",4) ||
19301  !std::strncmp(ss,"sum(",4) || !std::strncmp(ss,"avg(",4) ||
19302  !std::strncmp(ss,"std(",4) || !std::strncmp(ss,"variance(",9) ||
19303  !std::strncmp(ss,"prod(",5) || !std::strncmp(ss,"mean(",5) ||
19304  !std::strncmp(ss,"argmin(",7) || !std::strncmp(ss,"argmax(",7) ||
19305  !std::strncmp(ss,"argkth(",7)) { // Multi-argument functions
19306  _cimg_mp_op(*ss=='a'?(ss[1]=='v'?"Function 'avg()'":
19307  ss[3]=='k'?"Function 'argkth()'":
19308  ss[4]=='i'?"Function 'argmin()'":
19309  "Function 'argmax()'"):
19310  *ss=='s'?(ss[1]=='u'?"Function 'sum()'":"Function 'std()'"):
19311  *ss=='k'?"Function 'kth()'":
19312  *ss=='p'?"Function 'prod()'":
19313  *ss=='v'?"Function 'variance()'":
19314  ss[1]=='i'?"Function 'min()'":
19315  ss[1]=='a'?"Function 'max()'":
19316  ss[2]=='a'?"Function 'mean()'":"Function 'med()'");
19317  op = *ss=='a'?(ss[1]=='v'?mp_avg:ss[3]=='k'?mp_argkth:ss[4]=='i'?mp_argmin:mp_argmax):
19318  *ss=='s'?(ss[1]=='u'?mp_sum:mp_std):
19319  *ss=='k'?mp_kth:
19320  *ss=='p'?mp_prod:
19321  *ss=='v'?mp_variance:
19322  ss[1]=='i'?mp_min:
19323  ss[1]=='a'?mp_max:
19324  ss[2]=='a'?mp_mean:
19325  mp_median;
19326  is_sth = true; // Tell if all arguments are constant
19327  pos = scalar();
19328  CImg<ulongT>::vector((ulongT)op,pos,0).move_to(_opcode);
19329  for (s = std::strchr(ss,'(') + 1; s<se; ++s) {
19330  ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
19331  (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
19332  arg2 = compile(s,ns,depth1,0,is_single);
19333  if (_cimg_mp_is_vector(arg2))
19334  CImg<ulongT>::sequence(_cimg_mp_size(arg2),arg2 + 1,
19335  arg2 + (ulongT)_cimg_mp_size(arg2)).
19336  move_to(_opcode);
19337  else CImg<ulongT>::vector(arg2).move_to(_opcode);
19338  is_sth&=_cimg_mp_is_constant(arg2);
19339  s = ns;
19340  }
19341  (_opcode>'y').move_to(opcode);
19342  opcode[2] = opcode._height;
19343  if (is_sth) _cimg_mp_constant(op(*this));
19344  opcode.move_to(code);
19345  _cimg_mp_return(pos);
19346  }
19347 
19348  // No corresponding built-in function -> Look for a user-defined macro call.
19349  s0 = strchr(ss,'(');
19350  if (s0) {
19351  variable_name.assign(ss,(unsigned int)(s0 - ss + 1)).back() = 0;
19352 
19353  // Count number of specified arguments.
19354  p1 = 0;
19355  for (s = s0 + 1; s<=se1; ++p1, s = ns + 1) {
19356  while (*s && (signed char)*s<=' ') ++s;
19357  if (*s==')' && !p1) break;
19358  ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
19359  (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
19360  }
19361 
19362  arg3 = 0; // Number of possible name matches
19363  cimglist_for(macro_def,l) if (!std::strcmp(macro_def[l],variable_name) && ++arg3 &&
19364  macro_def[l].back()==(char)p1) {
19365  p2 = (unsigned int)macro_def[l].back(); // Number of required arguments
19366  CImg<charT> _expr = macro_body[l]; // Expression to be substituted
19367 
19368  p1 = 1; // Indice of current parsed argument
19369  for (s = s0 + 1; s<=se1; ++p1, s = ns + 1) { // Parse function arguments
19370  while (*s && (signed char)*s<=' ') ++s;
19371  if (*s==')' && p1==1) break; // Function has no arguments
19372  if (p1>p2) { ++p1; break; }
19373  ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
19374  (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
19375  variable_name.assign(s,(unsigned int)(ns - s + 1)).back() = 0; // Argument to write
19376  arg2 = 0;
19377  cimg_forX(_expr,k) {
19378  if (_expr[k]==(char)p1) { // Perform argument substitution
19379  arg1 = _expr._width;
19380  _expr.resize(arg1 + variable_name._width - 2,1,1,1,0);
19381  std::memmove(_expr._data + k + variable_name._width - 1,_expr._data + k + 1,arg1 - k - 1);
19382  std::memcpy(_expr._data + k,variable_name,variable_name._width - 1);
19383  k+=variable_name._width - 2;
19384  }
19385  ++arg2;
19386  }
19387  }
19388 
19389  // Recompute 'pexpr' and 'level' for evaluating substituted expression.
19390  CImg<charT> _pexpr(_expr._width);
19391  ns = _pexpr._data;
19392  for (ps = _expr._data, c1 = ' '; *ps; ++ps) {
19393  if ((signed char)*ps>' ') c1 = *ps;
19394  *(ns++) = c1;
19395  }
19396  *ns = 0;
19397 
19398  CImg<uintT> _level = get_level(_expr);
19399  expr.swap(_expr);
19400  pexpr.swap(_pexpr);
19401  level.swap(_level);
19402  s0 = user_macro;
19403  user_macro = macro_def[l];
19404  pos = compile(expr._data,expr._data + expr._width - 1,depth1,p_ref,is_single);
19405  user_macro = s0;
19406  level.swap(_level);
19407  pexpr.swap(_pexpr);
19408  expr.swap(_expr);
19409  _cimg_mp_return(pos);
19410  }
19411 
19412  if (arg3) { // Macro name matched but number of arguments does not
19413  CImg<uintT> sig_nargs(arg3);
19414  arg1 = 0;
19415  cimglist_for(macro_def,l) if (!std::strcmp(macro_def[l],variable_name))
19416  sig_nargs[arg1++] = (unsigned int)macro_def[l].back();
19417  *se = saved_char;
19418  cimg::strellipsize(variable_name,64);
19419  s0 = ss - 4>expr._data?ss - 4:expr._data;
19420  cimg::strellipsize(s0,64);
19421  if (sig_nargs._width>1) {
19422  sig_nargs.sort();
19423  arg1 = sig_nargs.back();
19424  --sig_nargs._width;
19425  throw CImgArgumentException("[" cimg_appname "_math_parser] "
19426  "CImg<%s>::%s: Function '%s()': Number of specified arguments (%u) "
19427  "does not match macro declaration (defined for %s or %u arguments), "
19428  "in expression '%s%s%s'.",
19429  pixel_type(),_cimg_mp_calling_function,variable_name._data,
19430  p1,sig_nargs.value_string()._data,arg1,
19431  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
19432  } else
19433  throw CImgArgumentException("[" cimg_appname "_math_parser] "
19434  "CImg<%s>::%s: Function '%s()': Number of specified arguments (%u) "
19435  "does not match macro declaration (defined for %u argument%s), "
19436  "in expression '%s%s%s'.",
19437  pixel_type(),_cimg_mp_calling_function,variable_name._data,
19438  p1,*sig_nargs,*sig_nargs!=1?"s":"",
19439  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
19440  }
19441  }
19442  } // if (se1==')')
19443 
19444  // Char / string initializer.
19445  if (*se1=='\'' &&
19446  ((se1>ss && *ss=='\'') ||
19447  (se1>ss1 && *ss=='_' && *ss1=='\''))) {
19448  if (*ss=='_') { _cimg_mp_op("Char initializer"); s1 = ss2; }
19449  else { _cimg_mp_op("String initializer"); s1 = ss1; }
19450  arg1 = (unsigned int)(se1 - s1); // Original string length.
19451  if (arg1) {
19452  CImg<charT>(s1,arg1 + 1).move_to(variable_name).back() = 0;
19453  cimg::strunescape(variable_name);
19454  arg1 = (unsigned int)std::strlen(variable_name);
19455  }
19456  if (!arg1) _cimg_mp_return(0); // Empty string -> 0
19457  if (*ss=='_') {
19458  if (arg1==1) _cimg_mp_constant(*variable_name);
19459  *se = saved_char;
19460  cimg::strellipsize(variable_name,64);
19461  s0 = ss - 4>expr._data?ss - 4:expr._data;
19462  cimg::strellipsize(s0,64);
19463  throw CImgArgumentException("[" cimg_appname "_math_parser] "
19464  "CImg<%s>::%s: %s: Literal %s contains more than one character, "
19465  "in expression '%s%s%s'.",
19466  pixel_type(),_cimg_mp_calling_function,s_op,
19467  ss1,
19468  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
19469  }
19470  pos = vector(arg1);
19471  CImg<ulongT>::vector((ulongT)mp_string_init,pos,arg1).move_to(_opcode);
19472  CImg<ulongT>(1,arg1/sizeof(ulongT) + (arg1%sizeof(ulongT)?1:0)).move_to(_opcode);
19473  std::memcpy((char*)_opcode[1]._data,variable_name,arg1);
19474  (_opcode>'y').move_to(code);
19475  _cimg_mp_return(pos);
19476  }
19477 
19478  // Vector initializer [ ... ].
19479  if (*ss=='[' && *se1==']') {
19480  _cimg_mp_op("Vector initializer");
19481  s1 = ss1; while (s1<se2 && (signed char)*s1<=' ') ++s1;
19482  s2 = se2; while (s2>s1 && (signed char)*s2<=' ') --s2;
19483  if (s2>s1 && *s1=='\'' && *s2=='\'') { // Vector values provided as a string
19484  arg1 = (unsigned int)(s2 - s1 - 1); // Original string length.
19485  if (arg1) {
19486  CImg<charT>(s1 + 1,arg1 + 1).move_to(variable_name).back() = 0;
19487  cimg::strunescape(variable_name);
19488  arg1 = (unsigned int)std::strlen(variable_name);
19489  }
19490  if (!arg1) _cimg_mp_return(0); // Empty string -> 0
19491  pos = vector(arg1);
19492  CImg<ulongT>::vector((ulongT)mp_string_init,pos,arg1).move_to(_opcode);
19493  CImg<ulongT>(1,arg1/sizeof(ulongT) + (arg1%sizeof(ulongT)?1:0)).move_to(_opcode);
19494  std::memcpy((char*)_opcode[1]._data,variable_name,arg1);
19495  (_opcode>'y').move_to(code);
19496  } else { // Vector values provided as list of items
19497  arg1 = 0; // Number of specified values.
19498  if (*ss1!=']') for (s = ss1; s<se; ++s) {
19499  ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
19500  (*ns!=']' || level[ns - expr._data]!=clevel)) ++ns;
19501  arg2 = compile(s,ns,depth1,0,is_single);
19502  if (_cimg_mp_is_vector(arg2)) {
19503  arg3 = _cimg_mp_size(arg2);
19504  CImg<ulongT>::sequence(arg3,arg2 + 1,arg2 + arg3).move_to(_opcode);
19505  arg1+=arg3;
19506  } else { CImg<ulongT>::vector(arg2).move_to(_opcode); ++arg1; }
19507  s = ns;
19508  }
19509  _cimg_mp_check_vector0(arg1);
19510  pos = vector(arg1);
19511  _opcode.insert(CImg<ulongT>::vector((ulongT)mp_vector_init,pos,0,arg1),0);
19512  (_opcode>'y').move_to(opcode);
19513  opcode[2] = opcode._height;
19514  opcode.move_to(code);
19515  }
19516  _cimg_mp_return(pos);
19517  }
19518 
19519  // Variables related to the input list of images.
19520  if (*ss1=='#' && ss2<se) {
19521  arg1 = compile(ss2,se,depth1,0,is_single);
19522  p1 = (unsigned int)(listin._width && _cimg_mp_is_constant(arg1)?cimg::mod((int)mem[arg1],listin.width()):~0U);
19523  switch (*ss) {
19524  case 'w' : // w#ind
19525  if (!listin) _cimg_mp_return(0);
19526  if (p1!=~0U) _cimg_mp_constant(listin[p1]._width);
19527  _cimg_mp_scalar1(mp_list_width,arg1);
19528  case 'h' : // h#ind
19529  if (!listin) _cimg_mp_return(0);
19530  if (p1!=~0U) _cimg_mp_constant(listin[p1]._height);
19531  _cimg_mp_scalar1(mp_list_height,arg1);
19532  case 'd' : // d#ind
19533  if (!listin) _cimg_mp_return(0);
19534  if (p1!=~0U) _cimg_mp_constant(listin[p1]._depth);
19535  _cimg_mp_scalar1(mp_list_depth,arg1);
19536  case 'r' : // r#ind
19537  if (!listin) _cimg_mp_return(0);
19538  if (p1!=~0U) _cimg_mp_constant(listin[p1]._is_shared);
19539  _cimg_mp_scalar1(mp_list_is_shared,arg1);
19540  case 's' : // s#ind
19541  if (!listin) _cimg_mp_return(0);
19542  if (p1!=~0U) _cimg_mp_constant(listin[p1]._spectrum);
19543  _cimg_mp_scalar1(mp_list_spectrum,arg1);
19544  case 'i' : // i#ind
19545  if (!listin) _cimg_mp_return(0);
19546  _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,_cimg_mp_slot_c,
19547  0,_cimg_mp_boundary);
19548  case 'I' : // I#ind
19549  p2 = p1!=~0U?listin[p1]._spectrum:listin._width?~0U:0;
19550  _cimg_mp_check_vector0(p2);
19551  pos = vector(p2);
19552  CImg<ulongT>::vector((ulongT)mp_list_Joff,pos,p1,0,0,p2).move_to(code);
19553  _cimg_mp_return(pos);
19554  case 'R' : // R#ind
19555  if (!listin) _cimg_mp_return(0);
19556  _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,0,
19557  0,_cimg_mp_boundary);
19558  case 'G' : // G#ind
19559  if (!listin) _cimg_mp_return(0);
19560  _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,1,
19561  0,_cimg_mp_boundary);
19562  case 'B' : // B#ind
19563  if (!listin) _cimg_mp_return(0);
19564  _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,2,
19565  0,_cimg_mp_boundary);
19566  case 'A' : // A#ind
19567  if (!listin) _cimg_mp_return(0);
19568  _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,3,
19569  0,_cimg_mp_boundary);
19570  }
19571  }
19572 
19573  if (*ss1 && *ss2=='#' && ss3<se) {
19574  arg1 = compile(ss3,se,depth1,0,is_single);
19575  p1 = (unsigned int)(listin._width && _cimg_mp_is_constant(arg1)?cimg::mod((int)mem[arg1],listin.width()):~0U);
19576  if (*ss=='w' && *ss1=='h') { // wh#ind
19577  if (!listin) _cimg_mp_return(0);
19578  if (p1!=~0U) _cimg_mp_constant(listin[p1]._width*listin[p1]._height);
19579  _cimg_mp_scalar1(mp_list_wh,arg1);
19580  }
19581  arg2 = ~0U;
19582 
19583  if (*ss=='i') {
19584  if (*ss1=='c') { // ic#ind
19585  if (!listin) _cimg_mp_return(0);
19586  if (_cimg_mp_is_constant(arg1)) {
19587  if (!list_median) list_median.assign(listin._width);
19588  if (!list_median[p1]) CImg<doubleT>::vector(listin[p1].median()).move_to(list_median[p1]);
19589  _cimg_mp_constant(*list_median[p1]);
19590  }
19591  _cimg_mp_scalar1(mp_list_median,arg1);
19592  }
19593  if (*ss1>='0' && *ss1<='9') { // i0#ind...i9#ind
19594  if (!listin) _cimg_mp_return(0);
19595  _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,*ss1 - '0',
19596  0,_cimg_mp_boundary);
19597  }
19598  switch (*ss1) {
19599  case 'm' : arg2 = 0; break; // im#ind
19600  case 'M' : arg2 = 1; break; // iM#ind
19601  case 'a' : arg2 = 2; break; // ia#ind
19602  case 'v' : arg2 = 3; break; // iv#ind
19603  case 's' : arg2 = 12; break; // is#ind
19604  case 'p' : arg2 = 13; break; // ip#ind
19605  }
19606  } else if (*ss1=='m') switch (*ss) {
19607  case 'x' : arg2 = 4; break; // xm#ind
19608  case 'y' : arg2 = 5; break; // ym#ind
19609  case 'z' : arg2 = 6; break; // zm#ind
19610  case 'c' : arg2 = 7; break; // cm#ind
19611  } else if (*ss1=='M') switch (*ss) {
19612  case 'x' : arg2 = 8; break; // xM#ind
19613  case 'y' : arg2 = 9; break; // yM#ind
19614  case 'z' : arg2 = 10; break; // zM#ind
19615  case 'c' : arg2 = 11; break; // cM#ind
19616  }
19617  if (arg2!=~0U) {
19618  if (!listin) _cimg_mp_return(0);
19619  if (_cimg_mp_is_constant(arg1)) {
19620  if (!list_stats) list_stats.assign(listin._width);
19621  if (!list_stats[p1]) list_stats[p1].assign(1,14,1,1,0).fill(listin[p1].get_stats(),false);
19622  _cimg_mp_constant(list_stats(p1,arg2));
19623  }
19624  _cimg_mp_scalar2(mp_list_stats,arg1,arg2);
19625  }
19626  }
19627 
19628  if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='#' && ss4<se) { // whd#ind
19629  arg1 = compile(ss4,se,depth1,0,is_single);
19630  if (!listin) _cimg_mp_return(0);
19631  p1 = (unsigned int)(_cimg_mp_is_constant(arg1)?cimg::mod((int)mem[arg1],listin.width()):~0U);
19632  if (p1!=~0U) _cimg_mp_constant(listin[p1]._width*listin[p1]._height*listin[p1]._depth);
19633  _cimg_mp_scalar1(mp_list_whd,arg1);
19634  }
19635  if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='s' && *ss4=='#' && ss5<se) { // whds#ind
19636  arg1 = compile(ss5,se,depth1,0,is_single);
19637  if (!listin) _cimg_mp_return(0);
19638  p1 = (unsigned int)(_cimg_mp_is_constant(arg1)?cimg::mod((int)mem[arg1],listin.width()):~0U);
19639  if (p1!=~0U) _cimg_mp_constant(listin[p1]._width*listin[p1]._height*listin[p1]._depth*listin[p1]._spectrum);
19640  _cimg_mp_scalar1(mp_list_whds,arg1);
19641  }
19642 
19643  if (!std::strcmp(ss,"interpolation")) _cimg_mp_return(_cimg_mp_interpolation); // interpolation
19644  if (!std::strcmp(ss,"boundary")) _cimg_mp_return(_cimg_mp_boundary); // boundary
19645 
19646  // No known item found, assuming this is an already initialized variable.
19647  variable_name.assign(ss,(unsigned int)(se - ss + 1)).back() = 0;
19648  if (variable_name[1]) { // Multi-char variable
19649  cimglist_for(variable_def,i) if (!std::strcmp(variable_name,variable_def[i]))
19650  _cimg_mp_return(variable_pos[i]);
19651  } else if (reserved_label[*variable_name]!=~0U) // Single-char variable
19652  _cimg_mp_return(reserved_label[*variable_name]);
19653 
19654  // Reached an unknown item -> error.
19655  is_sth = true; // is_valid_variable_name
19656  if (*variable_name>='0' && *variable_name<='9') is_sth = false;
19657  else for (ns = variable_name._data; *ns; ++ns)
19658  if (!is_varchar(*ns)) { is_sth = false; break; }
19659 
19660  *se = saved_char;
19661  c1 = *se1;
19662  cimg::strellipsize(variable_name,64);
19663  s0 = ss - 4>expr._data?ss - 4:expr._data;
19664  cimg::strellipsize(s0,64);
19665  if (is_sth)
19666  throw CImgArgumentException("[" cimg_appname "_math_parser] "
19667  "CImg<%s>::%s: Undefined variable '%s' in expression '%s%s%s'.",
19668  pixel_type(),_cimg_mp_calling_function,
19669  variable_name._data,
19670  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
19671  s1 = std::strchr(ss,'(');
19672  s_op = s1 && c1==')'?"function call":"item";
19673  throw CImgArgumentException("[" cimg_appname "_math_parser] "
19674  "CImg<%s>::%s: Unrecognized %s '%s' in expression '%s%s%s'.",
19675  pixel_type(),_cimg_mp_calling_function,
19676  s_op,variable_name._data,
19677  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
19678  }
19679 
19680  // Evaluation procedure.
19681  double operator()(const double x, const double y, const double z, const double c) {
19682  mem[_cimg_mp_slot_x] = x; mem[_cimg_mp_slot_y] = y; mem[_cimg_mp_slot_z] = z; mem[_cimg_mp_slot_c] = c;
19683  for (p_code = code; p_code<p_code_end; ++p_code) {
19684  opcode._data = p_code->_data;
19685  const ulongT target = opcode[1];
19686  mem[target] = _cimg_mp_defunc(*this);
19687  }
19688  return *result;
19689  }
19690 
19691  // Evaluation procedure (return output values in vector 'output').
19692  template<typename t>
19693  void operator()(const double x, const double y, const double z, const double c, t *const output) {
19694  mem[_cimg_mp_slot_x] = x; mem[_cimg_mp_slot_y] = y; mem[_cimg_mp_slot_z] = z; mem[_cimg_mp_slot_c] = c;
19695  for (p_code = code; p_code<p_code_end; ++p_code) {
19696  opcode._data = p_code->_data;
19697  const ulongT target = opcode[1];
19698  mem[target] = _cimg_mp_defunc(*this);
19699  }
19700  if (result_dim) {
19701  const double *ptrs = result + 1;
19702  t *ptrd = output;
19703  for (unsigned int k = 0; k<result_dim; ++k) *(ptrd++) = (t)*(ptrs++);
19704  } else *output = (t)*result;
19705  }
19706 
19707  // Evaluation procedure for the end() blocks.
19708  void end() {
19709  if (code_end.is_empty()) return;
19710  if (imgin) {
19711  mem[_cimg_mp_slot_x] = imgin._width - 1.0;
19712  mem[_cimg_mp_slot_y] = imgin._height - 1.0f;
19713  mem[_cimg_mp_slot_z] = imgin._depth - 1.0f;
19714  mem[_cimg_mp_slot_c] = imgin._spectrum - 1.0f;
19715  } else mem[_cimg_mp_slot_x] = mem[_cimg_mp_slot_y] = mem[_cimg_mp_slot_z] = mem[_cimg_mp_slot_c] = 0;
19716  p_code_end = code_end.end();
19717  for (p_code = code_end; p_code<p_code_end; ++p_code) {
19718  opcode._data = p_code->_data;
19719  const ulongT target = opcode[1];
19720  mem[target] = _cimg_mp_defunc(*this);
19721  }
19722  }
19723 
19724  // Return type of a memory element as a string.
19725  CImg<charT> s_type(const unsigned int arg) const {
19726  CImg<charT> res;
19727  if (_cimg_mp_is_vector(arg)) { // Vector
19728  CImg<charT>::string("vectorXXXXXXXXXXXXXXXX").move_to(res);
19729  std::sprintf(res._data + 6,"%u",_cimg_mp_size(arg));
19730  } else CImg<charT>::string("scalar").move_to(res);
19731  return res;
19732  }
19733 
19734  // Insert constant value in memory.
19735  unsigned int constant(const double val) {
19736 
19737  // Search for built-in constant.
19738  if (val==(double)(int)val) {
19739  if (val>=0 && val<=10) return (unsigned int)val;
19740  if (val<0 && val>=-5) return (unsigned int)(10 - val);
19741  }
19742  if (val==0.5) return 16;
19743  if (cimg::type<double>::is_nan(val)) return _cimg_mp_slot_nan;
19744 
19745  // Search for constant already requested before (in const cache).
19746  unsigned int ind = ~0U;
19747  if (constcache_size<1024) {
19748  if (!constcache_size) {
19749  constcache_vals.assign(16,1,1,1,0);
19750  constcache_inds.assign(16,1,1,1,0);
19751  *constcache_vals = val;
19752  constcache_size = 1;
19753  ind = 0;
19754  } else { // Dichotomic search
19755  const double val_beg = *constcache_vals, val_end = constcache_vals[constcache_size - 1];
19756  if (val_beg>=val) ind = 0;
19757  else if (val_end==val) ind = constcache_size - 1;
19758  else if (val_end<val) ind = constcache_size;
19759  else {
19760  unsigned int i0 = 1, i1 = constcache_size - 2;
19761  while (i0<=i1) {
19762  const unsigned int mid = (i0 + i1)/2;
19763  if (constcache_vals[mid]==val) { i0 = mid; break; }
19764  else if (constcache_vals[mid]<val) i0 = mid + 1;
19765  else i1 = mid - 1;
19766  }
19767  ind = i0;
19768  }
19769 
19770  if (ind>=constcache_size || constcache_vals[ind]!=val) {
19771  ++constcache_size;
19772  if (constcache_size>constcache_vals._width) {
19773  constcache_vals.resize(-200,1,1,1,0);
19774  constcache_inds.resize(-200,1,1,1,0);
19775  }
19776  const int l = constcache_size - (int)ind - 1;
19777  if (l>0) {
19778  std::memmove(&constcache_vals[ind + 1],&constcache_vals[ind],l*sizeof(double));
19779  std::memmove(&constcache_inds[ind + 1],&constcache_inds[ind],l*sizeof(unsigned int));
19780  }
19781  constcache_vals[ind] = val;
19782  constcache_inds[ind] = 0;
19783  }
19784  }
19785  if (constcache_inds[ind]) return constcache_inds[ind];
19786  }
19787 
19788  // Insert new constant in memory if necessary.
19789  if (mempos>=mem._width) { mem.resize(-200,1,1,1,0); memtype.resize(-200,1,1,1,0); }
19790  const unsigned int pos = mempos++;
19791  mem[pos] = val;
19792  memtype[pos] = 1; // Set constant property
19793  if (ind!=~0U) constcache_inds[ind] = pos;
19794  return pos;
19795  }
19796 
19797  // Insert code instructions for processing scalars.
19798  unsigned int scalar() { // Insert new scalar in memory.
19799  if (mempos>=mem._width) { mem.resize(-200,1,1,1,0); memtype.resize(mem._width,1,1,1,0); }
19800  return mempos++;
19801  }
19802 
19803  unsigned int scalar0(const mp_func op) {
19804  const unsigned int pos = scalar();
19805  CImg<ulongT>::vector((ulongT)op,pos).move_to(code);
19806  return pos;
19807  }
19808 
19809  unsigned int scalar1(const mp_func op, const unsigned int arg1) {
19810  const unsigned int pos =
19811  arg1>_cimg_mp_slot_c && _cimg_mp_is_comp(arg1) && op!=mp_copy?arg1:scalar();
19812  CImg<ulongT>::vector((ulongT)op,pos,arg1).move_to(code);
19813  return pos;
19814  }
19815 
19816  unsigned int scalar2(const mp_func op, const unsigned int arg1, const unsigned int arg2) {
19817  const unsigned int pos =
19818  arg1>_cimg_mp_slot_c && _cimg_mp_is_comp(arg1)?arg1:
19819  arg2>_cimg_mp_slot_c && _cimg_mp_is_comp(arg2)?arg2:scalar();
19820  CImg<ulongT>::vector((ulongT)op,pos,arg1,arg2).move_to(code);
19821  return pos;
19822  }
19823 
19824  unsigned int scalar3(const mp_func op,
19825  const unsigned int arg1, const unsigned int arg2, const unsigned int arg3) {
19826  const unsigned int pos =
19827  arg1>_cimg_mp_slot_c && _cimg_mp_is_comp(arg1)?arg1:
19828  arg2>_cimg_mp_slot_c && _cimg_mp_is_comp(arg2)?arg2:
19829  arg3>_cimg_mp_slot_c && _cimg_mp_is_comp(arg3)?arg3:scalar();
19830  CImg<ulongT>::vector((ulongT)op,pos,arg1,arg2,arg3).move_to(code);
19831  return pos;
19832  }
19833 
19834  unsigned int scalar4(const mp_func op,
19835  const unsigned int arg1, const unsigned int arg2, const unsigned int arg3,
19836  const unsigned int arg4) {
19837  const unsigned int pos =
19838  arg1>_cimg_mp_slot_c && _cimg_mp_is_comp(arg1)?arg1:
19839  arg2>_cimg_mp_slot_c && _cimg_mp_is_comp(arg2)?arg2:
19840  arg3>_cimg_mp_slot_c && _cimg_mp_is_comp(arg3)?arg3:
19841  arg4>_cimg_mp_slot_c && _cimg_mp_is_comp(arg4)?arg4:scalar();
19842  CImg<ulongT>::vector((ulongT)op,pos,arg1,arg2,arg3,arg4).move_to(code);
19843  return pos;
19844  }
19845 
19846  unsigned int scalar5(const mp_func op,
19847  const unsigned int arg1, const unsigned int arg2, const unsigned int arg3,
19848  const unsigned int arg4, const unsigned int arg5) {
19849  const unsigned int pos =
19850  arg1>_cimg_mp_slot_c && _cimg_mp_is_comp(arg1)?arg1:
19851  arg2>_cimg_mp_slot_c && _cimg_mp_is_comp(arg2)?arg2:
19852  arg3>_cimg_mp_slot_c && _cimg_mp_is_comp(arg3)?arg3:
19853  arg4>_cimg_mp_slot_c && _cimg_mp_is_comp(arg4)?arg4:
19854  arg5>_cimg_mp_slot_c && _cimg_mp_is_comp(arg5)?arg5:scalar();
19855  CImg<ulongT>::vector((ulongT)op,pos,arg1,arg2,arg3,arg4,arg5).move_to(code);
19856  return pos;
19857  }
19858 
19859  unsigned int scalar6(const mp_func op,
19860  const unsigned int arg1, const unsigned int arg2, const unsigned int arg3,
19861  const unsigned int arg4, const unsigned int arg5, const unsigned int arg6) {
19862  const unsigned int pos =
19863  arg1>_cimg_mp_slot_c && _cimg_mp_is_comp(arg1)?arg1:
19864  arg2>_cimg_mp_slot_c && _cimg_mp_is_comp(arg2)?arg2:
19865  arg3>_cimg_mp_slot_c && _cimg_mp_is_comp(arg3)?arg3:
19866  arg4>_cimg_mp_slot_c && _cimg_mp_is_comp(arg4)?arg4:
19867  arg5>_cimg_mp_slot_c && _cimg_mp_is_comp(arg5)?arg5:
19868  arg6>_cimg_mp_slot_c && _cimg_mp_is_comp(arg6)?arg6:scalar();
19869  CImg<ulongT>::vector((ulongT)op,pos,arg1,arg2,arg3,arg4,arg5,arg6).move_to(code);
19870  return pos;
19871  }
19872 
19873  unsigned int scalar7(const mp_func op,
19874  const unsigned int arg1, const unsigned int arg2, const unsigned int arg3,
19875  const unsigned int arg4, const unsigned int arg5, const unsigned int arg6,
19876  const unsigned int arg7) {
19877  const unsigned int pos =
19878  arg1>_cimg_mp_slot_c && _cimg_mp_is_comp(arg1)?arg1:
19879  arg2>_cimg_mp_slot_c && _cimg_mp_is_comp(arg2)?arg2:
19880  arg3>_cimg_mp_slot_c && _cimg_mp_is_comp(arg3)?arg3:
19881  arg4>_cimg_mp_slot_c && _cimg_mp_is_comp(arg4)?arg4:
19882  arg5>_cimg_mp_slot_c && _cimg_mp_is_comp(arg5)?arg5:
19883  arg6>_cimg_mp_slot_c && _cimg_mp_is_comp(arg6)?arg6:
19884  arg7>_cimg_mp_slot_c && _cimg_mp_is_comp(arg7)?arg7:scalar();
19885  CImg<ulongT>::vector((ulongT)op,pos,arg1,arg2,arg3,arg4,arg5,arg6,arg7).move_to(code);
19886  return pos;
19887  }
19888 
19889  // Return a string that defines the calling function + the user-defined function scope.
19890  CImg<charT> calling_function_s() const {
19891  CImg<charT> res;
19892  const unsigned int
19893  l1 = calling_function?(unsigned int)std::strlen(calling_function):0U,
19894  l2 = user_macro?(unsigned int)std::strlen(user_macro):0U;
19895  if (l2) {
19896  res.assign(l1 + l2 + 48);
19897  cimg_snprintf(res,res._width,"%s(): When substituting function '%s()'",calling_function,user_macro);
19898  } else {
19899  res.assign(l1 + l2 + 4);
19900  cimg_snprintf(res,res._width,"%s()",calling_function);
19901  }
19902  return res;
19903  }
19904 
19905  // Return true if specified argument can be a part of an allowed variable name.
19906  bool is_varchar(const char c) const {
19907  return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_';
19908  }
19909 
19910  // Insert code instructions for processing vectors.
19911  bool is_comp_vector(const unsigned int arg) const {
19912  unsigned int siz = _cimg_mp_size(arg);
19913  if (siz>8) return false;
19914  const int *ptr = memtype.data(arg + 1);
19915  bool is_tmp = true;
19916  while (siz-->0) if (*(ptr++)) { is_tmp = false; break; }
19917  return is_tmp;
19918  }
19919 
19920  void set_variable_vector(const unsigned int arg) {
19921  unsigned int siz = _cimg_mp_size(arg);
19922  int *ptr = memtype.data(arg + 1);
19923  while (siz-->0) *(ptr++) = -1;
19924  }
19925 
19926  unsigned int vector(const unsigned int siz) { // Insert new vector of specified size in memory
19927  if (mempos + siz>=mem._width) {
19928  mem.resize(2*mem._width + siz,1,1,1,0);
19929  memtype.resize(mem._width,1,1,1,0);
19930  }
19931  const unsigned int pos = mempos++;
19932  mem[pos] = cimg::type<double>::nan();
19933  memtype[pos] = siz + 1;
19934  mempos+=siz;
19935  return pos;
19936  }
19937 
19938  unsigned int vector(const unsigned int siz, const double value) { // Insert new initialized vector
19939  const unsigned int pos = vector(siz);
19940  double *ptr = &mem[pos] + 1;
19941  for (unsigned int i = 0; i<siz; ++i) *(ptr++) = value;
19942  return pos;
19943  }
19944 
19945  unsigned int vector_copy(const unsigned int arg) { // Insert new copy of specified vector in memory
19946  const unsigned int
19947  siz = _cimg_mp_size(arg),
19948  pos = vector(siz);
19949  CImg<ulongT>::vector((ulongT)mp_vector_copy,pos,arg,siz).move_to(code);
19950  return pos;
19951  }
19952 
19953  void self_vector_s(const unsigned int pos, const mp_func op, const unsigned int arg1) {
19954  const unsigned int siz = _cimg_mp_size(pos);
19955  if (siz>24) CImg<ulongT>::vector((ulongT)mp_self_map_vector_s,pos,siz,(ulongT)op,arg1).move_to(code);
19956  else {
19957  code.insert(siz);
19958  for (unsigned int k = 1; k<=siz; ++k)
19959  CImg<ulongT>::vector((ulongT)op,pos + k,arg1).move_to(code[code._width - 1 - siz + k]);
19960  }
19961  }
19962 
19963  void self_vector_v(const unsigned int pos, const mp_func op, const unsigned int arg1) {
19964  const unsigned int siz = _cimg_mp_size(pos);
19965  if (siz>24) CImg<ulongT>::vector((ulongT)mp_self_map_vector_v,pos,siz,(ulongT)op,arg1).move_to(code);
19966  else {
19967  code.insert(siz);
19968  for (unsigned int k = 1; k<=siz; ++k)
19969  CImg<ulongT>::vector((ulongT)op,pos + k,arg1 + k).move_to(code[code._width - 1 - siz + k]);
19970  }
19971  }
19972 
19973  unsigned int vector1_v(const mp_func op, const unsigned int arg1) {
19974  const unsigned int
19975  siz = _cimg_mp_size(arg1),
19976  pos = is_comp_vector(arg1)?arg1:vector(siz);
19977  if (siz>24) CImg<ulongT>::vector((ulongT)mp_vector_map_v,pos,siz,(ulongT)op,arg1).move_to(code);
19978  else {
19979  code.insert(siz);
19980  for (unsigned int k = 1; k<=siz; ++k)
19981  CImg<ulongT>::vector((ulongT)op,pos + k,arg1 + k).move_to(code[code._width - 1 - siz + k]);
19982  }
19983  return pos;
19984  }
19985 
19986  unsigned int vector2_vv(const mp_func op, const unsigned int arg1, const unsigned int arg2) {
19987  const unsigned int
19988  siz = _cimg_mp_size(arg1),
19989  pos = is_comp_vector(arg1)?arg1:is_comp_vector(arg2)?arg2:vector(siz);
19990  if (siz>24) CImg<ulongT>::vector((ulongT)mp_vector_map_vv,pos,siz,(ulongT)op,arg1,arg2).move_to(code);
19991  else {
19992  code.insert(siz);
19993  for (unsigned int k = 1; k<=siz; ++k)
19994  CImg<ulongT>::vector((ulongT)op,pos + k,arg1 + k,arg2 + k).move_to(code[code._width - 1 - siz + k]);
19995  }
19996  return pos;
19997  }
19998 
19999  unsigned int vector2_vs(const mp_func op, const unsigned int arg1, const unsigned int arg2) {
20000  const unsigned int
20001  siz = _cimg_mp_size(arg1),
20002  pos = is_comp_vector(arg1)?arg1:vector(siz);
20003  if (siz>24) CImg<ulongT>::vector((ulongT)mp_vector_map_vs,pos,siz,(ulongT)op,arg1,arg2).move_to(code);
20004  else {
20005  code.insert(siz);
20006  for (unsigned int k = 1; k<=siz; ++k)
20007  CImg<ulongT>::vector((ulongT)op,pos + k,arg1 + k,arg2).move_to(code[code._width - 1 - siz + k]);
20008  }
20009  return pos;
20010  }
20011 
20012  unsigned int vector2_sv(const mp_func op, const unsigned int arg1, const unsigned int arg2) {
20013  const unsigned int
20014  siz = _cimg_mp_size(arg2),
20015  pos = is_comp_vector(arg2)?arg2:vector(siz);
20016  if (siz>24) CImg<ulongT>::vector((ulongT)mp_vector_map_sv,pos,siz,(ulongT)op,arg1,arg2).move_to(code);
20017  else {
20018  code.insert(siz);
20019  for (unsigned int k = 1; k<=siz; ++k)
20020  CImg<ulongT>::vector((ulongT)op,pos + k,arg1,arg2 + k).move_to(code[code._width - 1 - siz + k]);
20021  }
20022  return pos;
20023  }
20024 
20025  unsigned int vector3_vss(const mp_func op, const unsigned int arg1, const unsigned int arg2,
20026  const unsigned int arg3) {
20027  const unsigned int
20028  siz = _cimg_mp_size(arg1),
20029  pos = is_comp_vector(arg1)?arg1:vector(siz);
20030  if (siz>24) CImg<ulongT>::vector((ulongT)mp_vector_map_vss,pos,siz,(ulongT)op,arg1,arg2,arg3).move_to(code);
20031  else {
20032  code.insert(siz);
20033  for (unsigned int k = 1; k<=siz; ++k)
20034  CImg<ulongT>::vector((ulongT)op,pos + k,arg1 + k,arg2,arg3).move_to(code[code._width - 1 - siz + k]);
20035  }
20036  return pos;
20037  }
20038 
20039  // Check if a memory slot is a positive integer constant scalar value.
20040  // 'mode' can be:
20041  // { 0=constant | 1=integer constant | 2=positive integer constant | 3=strictly-positive integer constant }
20042  void check_constant(const unsigned int arg, const unsigned int n_arg,
20043  const unsigned int mode,
20044  char *const ss, char *const se, const char saved_char) {
20045  _cimg_mp_check_type(arg,n_arg,1,0);
20046  if (!(_cimg_mp_is_constant(arg) &&
20047  (!mode || (double)(int)mem[arg]==mem[arg]) &&
20048  (mode<2 || mem[arg]>=(mode==3)))) {
20049  const char *s_arg = !n_arg?"":n_arg==1?"First ":n_arg==2?"Second ":n_arg==3?"Third ":
20050  n_arg==4?"Fourth ":n_arg==5?"Fifth ":n_arg==6?"Sixth ":n_arg==7?"Seventh ":n_arg==8?"Eighth ":
20051  n_arg==9?"Ninth ":"One of the ";
20052  *se = saved_char;
20053  char *const s0 = ss - 4>expr._data?ss - 4:expr._data;
20054  cimg::strellipsize(s0,64);
20055  throw CImgArgumentException("[" cimg_appname "_math_parser] "
20056  "CImg<%s>::%s: %s%s %s%s (of type '%s') is not a%s constant, "
20057  "in expression '%s%s%s'.",
20058  pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",
20059  s_arg,*s_arg?"argument":"Argument",s_type(arg)._data,
20060  !mode?"":mode==1?"n integer":
20061  mode==2?" positive integer":" strictly positive integer",
20062  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
20063  }
20064  }
20065 
20066  // Check a matrix is square.
20067  void check_matrix_square(const unsigned int arg, const unsigned int n_arg,
20068  char *const ss, char *const se, const char saved_char) {
20069  _cimg_mp_check_type(arg,n_arg,2,0);
20070  const unsigned int
20071  siz = _cimg_mp_size(arg),
20072  n = (unsigned int)std::sqrt((float)siz);
20073  if (n*n!=siz) {
20074  const char *s_arg;
20075  if (*s_op!='F') s_arg = !n_arg?"":n_arg==1?"Left-hand ":"Right-hand ";
20076  else s_arg = !n_arg?"":n_arg==1?"First ":n_arg==2?"Second ":n_arg==3?"Third ":"One ";
20077  *se = saved_char;
20078  char *const s0 = ss - 4>expr._data?ss - 4:expr._data;
20079  cimg::strellipsize(s0,64);
20080  throw CImgArgumentException("[" cimg_appname "_math_parser] "
20081  "CImg<%s>::%s: %s%s %s%s (of type '%s') "
20082  "cannot be considered as a square matrix, in expression '%s%s%s'.",
20083  pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",
20084  s_arg,*s_op=='F'?(*s_arg?"argument":"Argument"):(*s_arg?"operand":"Operand"),
20085  s_type(arg)._data,
20086  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
20087  }
20088  }
20089 
20090  // Check type compatibility for one argument.
20091  // Bits of 'mode' tells what types are allowed:
20092  // { 1 = scalar | 2 = vectorN }.
20093  // If 'N' is not zero, it also restricts the vectors to be of size N only.
20094  void check_type(const unsigned int arg, const unsigned int n_arg,
20095  const unsigned int mode, const unsigned int N,
20096  char *const ss, char *const se, const char saved_char) {
20097  const bool
20098  is_scalar = _cimg_mp_is_scalar(arg),
20099  is_vector = _cimg_mp_is_vector(arg) && (!N || _cimg_mp_size(arg)==N);
20100  bool cond = false;
20101  if (mode&1) cond|=is_scalar;
20102  if (mode&2) cond|=is_vector;
20103  if (!cond) {
20104  const char *s_arg;
20105  if (*s_op!='F') s_arg = !n_arg?"":n_arg==1?"Left-hand ":"Right-hand ";
20106  else s_arg = !n_arg?"":n_arg==1?"First ":n_arg==2?"Second ":n_arg==3?"Third ":
20107  n_arg==4?"Fourth ":n_arg==5?"Fifth ":n_arg==6?"Sixth ":n_arg==7?"Seventh ":n_arg==8?"Eighth":
20108  n_arg==9?"Ninth":"One of the ";
20109  CImg<charT> sb_type(32);
20110  if (mode==1) cimg_snprintf(sb_type,sb_type._width,"'scalar'");
20111  else if (mode==2) {
20112  if (N) cimg_snprintf(sb_type,sb_type._width,"'vector%u'",N);
20113  else cimg_snprintf(sb_type,sb_type._width,"'vector'");
20114  } else {
20115  if (N) cimg_snprintf(sb_type,sb_type._width,"'scalar' or 'vector%u'",N);
20116  else cimg_snprintf(sb_type,sb_type._width,"'scalar' or 'vector'");
20117  }
20118  *se = saved_char;
20119  char *const s0 = ss - 4>expr._data?ss - 4:expr._data;
20120  cimg::strellipsize(s0,64);
20121  throw CImgArgumentException("[" cimg_appname "_math_parser] "
20122  "CImg<%s>::%s: %s%s %s%s has invalid type '%s' (should be %s), "
20123  "in expression '%s%s%s'.",
20124  pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",
20125  s_arg,*s_op=='F'?(*s_arg?"argument":"Argument"):(*s_arg?"operand":"Operand"),
20126  s_type(arg)._data,sb_type._data,
20127  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
20128  }
20129  }
20130 
20131  // Check that listin or listout are not empty.
20132  void check_list(const bool is_out,
20133  char *const ss, char *const se, const char saved_char) {
20134  if ((!is_out && !listin) || (is_out && !listout)) {
20135  *se = saved_char;
20136  char *const s0 = ss - 4>expr._data?ss - 4:expr._data;
20137  cimg::strellipsize(s0,64);
20138  throw CImgArgumentException("[" cimg_appname "_math_parser] "
20139  "CImg<%s>::%s: %s%s Invalid call with an empty image list, "
20140  "in expression '%s%s%s'.",
20141  pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",
20142  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
20143  }
20144  }
20145 
20146  // Check a vector is not 0-dimensional, or with unknown dimension at compile time.
20147  void check_vector0(const unsigned int dim,
20148  char *const ss, char *const se, const char saved_char) {
20149  char *s0 = 0;
20150  if (!dim) {
20151  *se = saved_char;
20152  s0 = ss - 4>expr._data?ss - 4:expr._data;
20153  cimg::strellipsize(s0,64);
20154  throw CImgArgumentException("[" cimg_appname "_math_parser] "
20155  "CImg<%s>::%s: %s%s Invalid construction of a 0-dimensional vector, "
20156  "in expression '%s%s%s'.",
20157  pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",
20158  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
20159  } else if (dim==~0U) {
20160  *se = saved_char;
20161  s0 = ss - 4>expr._data?ss - 4:expr._data;
20162  cimg::strellipsize(s0,64);
20163  throw CImgArgumentException("[" cimg_appname "_math_parser] "
20164  "CImg<%s>::%s: %s%s Invalid construction of a vector with possible dynamic size, "
20165  "in expression '%s%s%s'.",
20166  pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",
20167  s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
20168  }
20169  }
20170 
20171  // Evaluation functions, known by the parser.
20172  // Defining these functions 'static' ensures that sizeof(mp_func)==sizeof(ulongT),
20173  // so we can store pointers to them directly in the opcode vectors.
20174 #ifdef _mp_arg
20175 #undef _mp_arg
20176 #endif
20177 #define _mp_arg(x) mp.mem[mp.opcode[x]]
20178 
20179  static double mp_abs(_cimg_math_parser& mp) {
20180  return cimg::abs(_mp_arg(2));
20181  }
20182 
20183  static double mp_add(_cimg_math_parser& mp) {
20184  return _mp_arg(2) + _mp_arg(3);
20185  }
20186 
20187  static double mp_acos(_cimg_math_parser& mp) {
20188  return std::acos(_mp_arg(2));
20189  }
20190 
20191  static double mp_arg(_cimg_math_parser& mp) {
20192  const int _ind = (int)_mp_arg(4);
20193  const unsigned int
20194  nb_args = (unsigned int)mp.opcode[2] - 4,
20195  ind = _ind<0?_ind + nb_args:(unsigned int)_ind,
20196  siz = (unsigned int)mp.opcode[3];
20197  if (siz>0) {
20198  if (ind>=nb_args) std::memset(&_mp_arg(1) + 1,0,siz*sizeof(double));
20199  else std::memcpy(&_mp_arg(1) + 1,&_mp_arg(ind + 4) + 1,siz*sizeof(double));
20200  return cimg::type<double>::nan();
20201  }
20202  if (ind>=nb_args) return 0;
20203  return _mp_arg(ind + 4);
20204  }
20205 
20206  static double mp_argkth(_cimg_math_parser& mp) {
20207  const unsigned int i_end = (unsigned int)mp.opcode[2];
20208  const double val = mp_kth(mp);
20209  for (unsigned int i = 4; i<i_end; ++i) if (val==_mp_arg(i)) return i - 3.0;
20210  return 1;
20211  }
20212 
20213  static double mp_argmin(_cimg_math_parser& mp) {
20214  const unsigned int i_end = (unsigned int)mp.opcode[2];
20215  double val = _mp_arg(3);
20216  unsigned int argval = 0;
20217  for (unsigned int i = 4; i<i_end; ++i) {
20218  const double _val = _mp_arg(i);
20219  if (_val<val) { val = _val; argval = i - 3; }
20220  }
20221  return (double)argval;
20222  }
20223 
20224  static double mp_argmax(_cimg_math_parser& mp) {
20225  const unsigned int i_end = (unsigned int)mp.opcode[2];
20226  double val = _mp_arg(3);
20227  unsigned int argval = 0;
20228  for (unsigned int i = 4; i<i_end; ++i) {
20229  const double _val = _mp_arg(i);
20230  if (_val>val) { val = _val; argval = i - 3; }
20231  }
20232  return (double)argval;
20233  }
20234 
20235  static double mp_asin(_cimg_math_parser& mp) {
20236  return std::asin(_mp_arg(2));
20237  }
20238 
20239  static double mp_atan(_cimg_math_parser& mp) {
20240  return std::atan(_mp_arg(2));
20241  }
20242 
20243  static double mp_atan2(_cimg_math_parser& mp) {
20244  return std::atan2(_mp_arg(2),_mp_arg(3));
20245  }
20246 
20247  static double mp_avg(_cimg_math_parser& mp) {
20248  const unsigned int i_end = (unsigned int)mp.opcode[2];
20249  double val = _mp_arg(3);
20250  for (unsigned int i = 4; i<i_end; ++i) val+=_mp_arg(i);
20251  return val/(i_end - 3);
20252  }
20253 
20254  static double mp_bitwise_and(_cimg_math_parser& mp) {
20255  return (double)((longT)_mp_arg(2) & (longT)_mp_arg(3));
20256  }
20257 
20258  static double mp_bitwise_left_shift(_cimg_math_parser& mp) {
20259  return (double)((longT)_mp_arg(2)<<(unsigned int)_mp_arg(3));
20260  }
20261 
20262  static double mp_bitwise_not(_cimg_math_parser& mp) {
20263  // Limit result to 32bits such that it can be entirely represented as a 'double'.
20264  return (double)~(unsigned int)_mp_arg(2);
20265  }
20266 
20267  static double mp_bitwise_or(_cimg_math_parser& mp) {
20268  return (double)((longT)_mp_arg(2) | (longT)_mp_arg(3));
20269  }
20270 
20271  static double mp_bitwise_right_shift(_cimg_math_parser& mp) {
20272  return (double)((longT)_mp_arg(2)>>(unsigned int)_mp_arg(3));
20273  }
20274 
20275  static double mp_bitwise_xor(_cimg_math_parser& mp) {
20276  return (double)((longT)_mp_arg(2) ^ (longT)_mp_arg(3));
20277  }
20278 
20279  static double mp_bool(_cimg_math_parser& mp) {
20280  return (double)(bool)_mp_arg(2);
20281  }
20282 
20283  static double mp_break(_cimg_math_parser& mp) {
20284  mp.break_type = 1;
20285  mp.p_code = mp.p_break - 1;
20286  return cimg::type<double>::nan();
20287  }
20288 
20289  static double mp_breakpoint(_cimg_math_parser& mp) {
20290  cimg_abort_init;
20291  cimg_abort_test;
20292  cimg::unused(mp);
20293  return cimg::type<double>::nan();
20294  }
20295 
20296  static double mp_cats(_cimg_math_parser& mp) {
20297  const double *ptrd = &_mp_arg(1) + 1;
20298  const unsigned int
20299  sizd = (unsigned int)mp.opcode[2],
20300  nb_args = (unsigned int)(mp.opcode[3] - 4)/2;
20301  CImgList<charT> _str;
20302  for (unsigned int n = 0; n<nb_args; ++n) {
20303  const unsigned int siz = (unsigned int)mp.opcode[5 + 2*n];
20304  if (siz) { // Vector argument
20305  const double *ptrs = &_mp_arg(4 + 2*n) + 1;
20306  unsigned int l = 0;
20307  while (l<siz && ptrs[l]) ++l;
20308  CImg<doubleT>(ptrs,l,1,1,1,true).move_to(_str);
20309  } else CImg<charT>::vector((char)_mp_arg(4 + 2*n)).move_to(_str); // Scalar argument
20310  }
20311  CImg(1,1,1,1,0).move_to(_str);
20312  const CImg<charT> str = _str>'x';
20313  const unsigned int l = std::min(str._width,sizd);
20314  CImg<doubleT>(ptrd,l,1,1,1,true) = str.get_shared_points(0,l - 1);
20315  return cimg::type<double>::nan();
20316  }
20317 
20318  static double mp_cbrt(_cimg_math_parser& mp) {
20319  return cimg::cbrt(_mp_arg(2));
20320  }
20321 
20322  static double mp_ceil(_cimg_math_parser& mp) {
20323  return std::ceil(_mp_arg(2));
20324  }
20325 
20326  static double mp_complex_abs(_cimg_math_parser& mp) {
20327  return cimg::_hypot(_mp_arg(2),_mp_arg(3));
20328  }
20329 
20330  static double mp_complex_conj(_cimg_math_parser& mp) {
20331  const double *ptrs = &_mp_arg(2) + 1;
20332  double *ptrd = &_mp_arg(1) + 1;
20333  *(ptrd++) = *(ptrs++);
20334  *ptrd = -*(ptrs);
20335  return cimg::type<double>::nan();
20336  }
20337 
20338  static double mp_complex_div_sv(_cimg_math_parser& mp) {
20339  const double
20340  *ptr2 = &_mp_arg(3) + 1,
20341  r1 = _mp_arg(2),
20342  r2 = *(ptr2++), i2 = *ptr2;
20343  double *ptrd = &_mp_arg(1) + 1;
20344  const double denom = r2*r2 + i2*i2;
20345  *(ptrd++) = r1*r2/denom;
20346  *ptrd = -r1*i2/denom;
20347  return cimg::type<double>::nan();
20348  }
20349 
20350  static double mp_complex_div_vv(_cimg_math_parser& mp) {
20351  const double
20352  *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1,
20353  r1 = *(ptr1++), i1 = *ptr1,
20354  r2 = *(ptr2++), i2 = *ptr2;
20355  double *ptrd = &_mp_arg(1) + 1;
20356  const double denom = r2*r2 + i2*i2;
20357  *(ptrd++) = (r1*r2 + i1*i2)/denom;
20358  *ptrd = (r2*i1 - r1*i2)/denom;
20359  return cimg::type<double>::nan();
20360  }
20361 
20362  static double mp_complex_exp(_cimg_math_parser& mp) {
20363  double *ptrd = &_mp_arg(1) + 1;
20364  const double *ptrs = &_mp_arg(2) + 1, r = *(ptrs++), i = *(ptrs), er = std::exp(r);
20365  *(ptrd++) = er*std::cos(i);
20366  *(ptrd++) = er*std::sin(i);
20367  return cimg::type<double>::nan();
20368  }
20369 
20370  static double mp_complex_log(_cimg_math_parser& mp) {
20371  double *ptrd = &_mp_arg(1) + 1;
20372  const double *ptrs = &_mp_arg(2) + 1, r = *(ptrs++), i = *(ptrs);
20373  *(ptrd++) = 0.5*std::log(r*r + i*i);
20374  *(ptrd++) = std::atan2(i,r);
20375  return cimg::type<double>::nan();
20376  }
20377 
20378  static double mp_complex_mul(_cimg_math_parser& mp) {
20379  const double
20380  *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1,
20381  r1 = *(ptr1++), i1 = *ptr1,
20382  r2 = *(ptr2++), i2 = *ptr2;
20383  double *ptrd = &_mp_arg(1) + 1;
20384  *(ptrd++) = r1*r2 - i1*i2;
20385  *(ptrd++) = r1*i2 + r2*i1;
20386  return cimg::type<double>::nan();
20387  }
20388 
20389  static void _mp_complex_pow(const double r1, const double i1,
20390  const double r2, const double i2,
20391  double *ptrd) {
20392  double ro, io;
20393  if (cimg::abs(i2)<1e-15) { // Exponent is real
20394  if (cimg::abs(r1)<1e-15 && cimg::abs(i1)<1e-15) {
20395  if (cimg::abs(r2)<1e-15) { ro = 1; io = 0; }
20396  else ro = io = 0;
20397  } else {
20398  const double
20399  mod1_2 = r1*r1 + i1*i1,
20400  phi1 = std::atan2(i1,r1),
20401  modo = std::pow(mod1_2,0.5*r2),
20402  phio = r2*phi1;
20403  ro = modo*std::cos(phio);
20404  io = modo*std::sin(phio);
20405  }
20406  } else { // Exponent is complex
20407  if (cimg::abs(r1)<1e-15 && cimg::abs(i1)<1e-15) ro = io = 0;
20408  const double
20409  mod1_2 = r1*r1 + i1*i1,
20410  phi1 = std::atan2(i1,r1),
20411  modo = std::pow(mod1_2,0.5*r2)*std::exp(-i2*phi1),
20412  phio = r2*phi1 + 0.5*i2*std::log(mod1_2);
20413  ro = modo*std::cos(phio);
20414  io = modo*std::sin(phio);
20415  }
20416  *(ptrd++) = ro;
20417  *ptrd = io;
20418  }
20419 
20420  static double mp_complex_pow_ss(_cimg_math_parser& mp) {
20421  const double val1 = _mp_arg(2), val2 = _mp_arg(3);
20422  double *ptrd = &_mp_arg(1) + 1;
20423  _mp_complex_pow(val1,0,val2,0,ptrd);
20424  return cimg::type<double>::nan();
20425  }
20426 
20427  static double mp_complex_pow_sv(_cimg_math_parser& mp) {
20428  const double val1 = _mp_arg(2), *ptr2 = &_mp_arg(3) + 1;
20429  double *ptrd = &_mp_arg(1) + 1;
20430  _mp_complex_pow(val1,0,ptr2[0],ptr2[1],ptrd);
20431  return cimg::type<double>::nan();
20432  }
20433 
20434  static double mp_complex_pow_vs(_cimg_math_parser& mp) {
20435  const double *ptr1 = &_mp_arg(2) + 1, val2 = _mp_arg(3);
20436  double *ptrd = &_mp_arg(1) + 1;
20437  _mp_complex_pow(ptr1[0],ptr1[1],val2,0,ptrd);
20438  return cimg::type<double>::nan();
20439  }
20440 
20441  static double mp_complex_pow_vv(_cimg_math_parser& mp) {
20442  const double *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1;
20443  double *ptrd = &_mp_arg(1) + 1;
20444  _mp_complex_pow(ptr1[0],ptr1[1],ptr2[0],ptr2[1],ptrd);
20445  return cimg::type<double>::nan();
20446  }
20447 
20448  static double mp_continue(_cimg_math_parser& mp) {
20449  mp.break_type = 2;
20450  mp.p_code = mp.p_break - 1;
20451  return cimg::type<double>::nan();
20452  }
20453 
20454  static double mp_cos(_cimg_math_parser& mp) {
20455  return std::cos(_mp_arg(2));
20456  }
20457 
20458  static double mp_cosh(_cimg_math_parser& mp) {
20459  return std::cosh(_mp_arg(2));
20460  }
20461 
20462  static double mp_critical(_cimg_math_parser& mp) {
20463  const double res = _mp_arg(1);
20464  cimg_pragma_openmp(critical(mp_critical))
20465  {
20466  for (const CImg<ulongT> *const p_end = ++mp.p_code + mp.opcode[2];
20467  mp.p_code<p_end; ++mp.p_code) { // Evaluate body
20468  mp.opcode._data = mp.p_code->_data;
20469  const ulongT target = mp.opcode[1];
20470  mp.mem[target] = _cimg_mp_defunc(mp);
20471  }
20472  }
20473  --mp.p_code;
20474  return res;
20475  }
20476 
20477  static double mp_crop(_cimg_math_parser& mp) {
20478  double *ptrd = &_mp_arg(1) + 1;
20479  const int x = (int)_mp_arg(3), y = (int)_mp_arg(4), z = (int)_mp_arg(5), c = (int)_mp_arg(6);
20480  const unsigned int
20481  dx = (unsigned int)mp.opcode[7],
20482  dy = (unsigned int)mp.opcode[8],
20483  dz = (unsigned int)mp.opcode[9],
20484  dc = (unsigned int)mp.opcode[10];
20485  const bool boundary_conditions = (bool)_mp_arg(11);
20486  unsigned int ind = (unsigned int)mp.opcode[2];
20487  if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
20488  const CImg<T> &img = ind==~0U?mp.imgin:mp.listin[ind];
20489  if (!img) std::memset(ptrd,0,dx*dy*dz*dc*sizeof(double));
20490  else CImg<doubleT>(ptrd,dx,dy,dz,dc,true) = img.get_crop(x,y,z,c,
20491  x + dx - 1,y + dy - 1,
20492  z + dz - 1,c + dc - 1,
20493  boundary_conditions);
20494  return cimg::type<double>::nan();
20495  }
20496 
20497  static double mp_cross(_cimg_math_parser& mp) {
20499  vout(&_mp_arg(1) + 1,1,3,1,1,true),
20500  v1(&_mp_arg(2) + 1,1,3,1,1,true),
20501  v2(&_mp_arg(3) + 1,1,3,1,1,true);
20502  (vout = v1).cross(v2);
20503  return cimg::type<double>::nan();
20504  }
20505 
20506  static double mp_cut(_cimg_math_parser& mp) {
20507  double val = _mp_arg(2), cmin = _mp_arg(3), cmax = _mp_arg(4);
20508  return val<cmin?cmin:val>cmax?cmax:val;
20509  }
20510 
20511  static double mp_date(_cimg_math_parser& mp) {
20512  const unsigned int
20513  _arg = (unsigned int)mp.opcode[3],
20514  _siz = (unsigned int)mp.opcode[4],
20515  siz = _siz?_siz:1;
20516  const double *const arg_in = _arg==~0U?0:&_mp_arg(3) + (_siz?1:0);
20517  double *const arg_out = &_mp_arg(1) + (_siz?1:0);
20518  if (arg_in) std::memcpy(arg_out,arg_in,siz*sizeof(double));
20519  else for (unsigned int i = 0; i<siz; ++i) arg_out[i] = i;
20520 
20521  CImg<charT> filename(mp.opcode[2] - 5);
20522  if (filename) {
20523  const ulongT *ptrs = mp.opcode._data + 5;
20524  cimg_for(filename,ptrd,char) *ptrd = (char)*(ptrs++);
20525  cimg::fdate(filename,arg_out,siz);
20526  } else cimg::date(arg_out,siz);
20527  return _siz?cimg::type<double>::nan():*arg_out;
20528  }
20529 
20530  static double mp_debug(_cimg_math_parser& mp) {
20531  CImg<charT> expr(mp.opcode[2] - 4);
20532  const ulongT *ptrs = mp.opcode._data + 4;
20533  cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++);
20534  cimg::strellipsize(expr);
20535  const ulongT g_target = mp.opcode[1];
20536 
20537 #ifndef cimg_use_openmp
20538  const unsigned int n_thread = 0;
20539 #else
20540  const unsigned int n_thread = omp_get_thread_num();
20541 #endif
20542  cimg_pragma_openmp(critical(mp_debug))
20543  {
20544  std::fprintf(cimg::output(),
20545  "\n[" cimg_appname "_math_parser] %p[thread #%u]:%*c"
20546  "Start debugging expression '%s', code length %u -> mem[%u] (memsize: %u)",
20547  (void*)&mp,n_thread,mp.debug_indent,' ',
20548  expr._data,(unsigned int)mp.opcode[3],(unsigned int)g_target,mp.mem._width);
20549  std::fflush(cimg::output());
20550  mp.debug_indent+=3;
20551  }
20552  const CImg<ulongT> *const p_end = (++mp.p_code) + mp.opcode[3];
20553  CImg<ulongT> _op;
20554  for ( ; mp.p_code<p_end; ++mp.p_code) {
20555  const CImg<ulongT> &op = *mp.p_code;
20556  mp.opcode._data = op._data;
20557 
20558  _op.assign(1,op._height - 1);
20559  const ulongT *ptrs = op._data + 1;
20560  for (ulongT *ptrd = _op._data, *const ptrde = _op._data + _op._height; ptrd<ptrde; ++ptrd)
20561  *ptrd = *(ptrs++);
20562 
20563  const ulongT target = mp.opcode[1];
20564  mp.mem[target] = _cimg_mp_defunc(mp);
20565  cimg_pragma_openmp(critical(mp_debug))
20566  {
20567  std::fprintf(cimg::output(),
20568  "\n[" cimg_appname "_math_parser] %p[thread #%u]:%*c"
20569  "Opcode %p = [ %p,%s ] -> mem[%u] = %g",
20570  (void*)&mp,n_thread,mp.debug_indent,' ',
20571  (void*)mp.opcode._data,(void*)*mp.opcode,_op.value_string().data(),
20572  (unsigned int)target,mp.mem[target]);
20573  std::fflush(cimg::output());
20574  }
20575  }
20576  cimg_pragma_openmp(critical(mp_debug))
20577  {
20578  mp.debug_indent-=3;
20579  std::fprintf(cimg::output(),
20580  "\n[" cimg_appname "_math_parser] %p[thread #%u]:%*c"
20581  "End debugging expression '%s' -> mem[%u] = %g (memsize: %u)",
20582  (void*)&mp,n_thread,mp.debug_indent,' ',
20583  expr._data,(unsigned int)g_target,mp.mem[g_target],mp.mem._width);
20584  std::fflush(cimg::output());
20585  }
20586  --mp.p_code;
20587  return mp.mem[g_target];
20588  }
20589 
20590  static double mp_decrement(_cimg_math_parser& mp) {
20591  return _mp_arg(2) - 1;
20592  }
20593 
20594  static double mp_det(_cimg_math_parser& mp) {
20595  const double *ptrs = &_mp_arg(2) + 1;
20596  const unsigned int k = (unsigned int)mp.opcode[3];
20597  return CImg<doubleT>(ptrs,k,k,1,1,true).det();
20598  }
20599 
20600  static double mp_diag(_cimg_math_parser& mp) {
20601  double *ptrd = &_mp_arg(1) + 1;
20602  const double *ptrs = &_mp_arg(2) + 1;
20603  const unsigned int k = (unsigned int)mp.opcode[3];
20604  CImg<doubleT>(ptrd,k,k,1,1,true) = CImg<doubleT>(ptrs,1,k,1,1,true).get_diagonal();
20605  return cimg::type<double>::nan();
20606  }
20607 
20608  static double mp_display_memory(_cimg_math_parser& mp) {
20609  cimg::unused(mp);
20610  std::fputc('\n',cimg::output());
20611  mp.mem.display("[" cimg_appname "_math_parser] Memory snapshot");
20612  return cimg::type<double>::nan();
20613  }
20614 
20615  static double mp_display(_cimg_math_parser& mp) {
20616  const unsigned int
20617  _siz = (unsigned int)mp.opcode[3],
20618  siz = _siz?_siz:1;
20619  const double *const ptr = &_mp_arg(1) + (_siz?1:0);
20620  const int
20621  w = (int)_mp_arg(4),
20622  h = (int)_mp_arg(5),
20623  d = (int)_mp_arg(6),
20624  s = (int)_mp_arg(7);
20625  CImg<doubleT> img;
20626  if (w>0 && h>0 && d>0 && s>0) {
20627  if ((unsigned int)w*h*d*s<=siz) img.assign(ptr,w,h,d,s,true);
20628  else img.assign(ptr,siz).resize(w,h,d,s,-1);
20629  } else img.assign(ptr,1,siz,1,1,true);
20630 
20631  CImg<charT> expr(mp.opcode[2] - 8);
20632  const ulongT *ptrs = mp.opcode._data + 8;
20633  cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++);
20634  ((CImg<charT>::string("[" cimg_appname "_math_parser] ",false,true),expr)>'x').move_to(expr);
20635  cimg::strellipsize(expr);
20636  std::fputc('\n',cimg::output());
20637  img.display(expr._data);
20638  return cimg::type<double>::nan();
20639  }
20640 
20641  static double mp_div(_cimg_math_parser& mp) {
20642  return _mp_arg(2)/_mp_arg(3);
20643  }
20644 
20645  static double mp_dot(_cimg_math_parser& mp) {
20646  const unsigned int siz = (unsigned int)mp.opcode[4];
20647  return CImg<doubleT>(&_mp_arg(2) + 1,1,siz,1,1,true).
20648  dot(CImg<doubleT>(&_mp_arg(3) + 1,1,siz,1,1,true));
20649  }
20650 
20651  static double mp_dowhile(_cimg_math_parser& mp) {
20652  const ulongT
20653  mem_body = mp.opcode[1],
20654  mem_cond = mp.opcode[2];
20655  const CImg<ulongT>
20656  *const p_body = ++mp.p_code,
20657  *const p_cond = p_body + mp.opcode[3],
20658  *const p_end = p_cond + mp.opcode[4];
20659  const unsigned int vsiz = (unsigned int)mp.opcode[5];
20660  if (mp.opcode[6]) { // Set default value for result and condition if necessary
20661  if (vsiz) CImg<doubleT>(&mp.mem[mem_body] + 1,vsiz,1,1,1,true).fill(cimg::type<double>::nan());
20662  else mp.mem[mem_body] = cimg::type<double>::nan();
20663  }
20664  if (mp.opcode[7]) mp.mem[mem_cond] = 0;
20665 
20666  const unsigned int _break_type = mp.break_type;
20667  mp.break_type = 0;
20668  do {
20669  for (mp.p_code = p_body; mp.p_code<p_cond; ++mp.p_code) { // Evaluate body
20670  mp.opcode._data = mp.p_code->_data;
20671  const ulongT target = mp.opcode[1];
20672  mp.mem[target] = _cimg_mp_defunc(mp);
20673  }
20674  if (mp.break_type==1) break; else if (mp.break_type==2) mp.break_type = 0;
20675  for (mp.p_code = p_cond; mp.p_code<p_end; ++mp.p_code) { // Evaluate condition
20676  mp.opcode._data = mp.p_code->_data;
20677  const ulongT target = mp.opcode[1];
20678  mp.mem[target] = _cimg_mp_defunc(mp);
20679  }
20680  if (mp.break_type==1) break; else if (mp.break_type==2) mp.break_type = 0;
20681  } while (mp.mem[mem_cond]);
20682  mp.break_type = _break_type;
20683  mp.p_code = p_end - 1;
20684  return mp.mem[mem_body];
20685  }
20686 
20687  static double mp_draw(_cimg_math_parser& mp) {
20688  const int x = (int)_mp_arg(4), y = (int)_mp_arg(5), z = (int)_mp_arg(6), c = (int)_mp_arg(7);
20689  unsigned int ind = (unsigned int)mp.opcode[3];
20690 
20691  if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(3),mp.listin.width());
20692  CImg<T> &img = ind==~0U?mp.imgout:mp.listout[ind];
20693  unsigned int
20694  dx = (unsigned int)mp.opcode[8],
20695  dy = (unsigned int)mp.opcode[9],
20696  dz = (unsigned int)mp.opcode[10],
20697  dc = (unsigned int)mp.opcode[11];
20698  dx = dx==~0U?img._width:(unsigned int)_mp_arg(8);
20699  dy = dy==~0U?img._height:(unsigned int)_mp_arg(9);
20700  dz = dz==~0U?img._depth:(unsigned int)_mp_arg(10);
20701  dc = dc==~0U?img._spectrum:(unsigned int)_mp_arg(11);
20702 
20703  const ulongT sizS = mp.opcode[2];
20704  if (sizS<(ulongT)dx*dy*dz*dc)
20705  throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'draw()': "
20706  "Sprite dimension (%lu values) and specified sprite geometry (%u,%u,%u,%u) "
20707  "(%lu values) do not match.",
20708  mp.imgin.pixel_type(),sizS,dx,dy,dz,dc,(ulongT)dx*dy*dz*dc);
20709  CImg<doubleT> S(&_mp_arg(1) + 1,dx,dy,dz,dc,true);
20710  const float opacity = (float)_mp_arg(12);
20711 
20712  if (img._data) {
20713  if (mp.opcode[13]!=~0U) { // Opacity mask specified
20714  const ulongT sizM = mp.opcode[14];
20715  if (sizM<(ulongT)dx*dy*dz)
20716  throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'draw()': "
20717  "Mask dimension (%lu values) and specified sprite geometry (%u,%u,%u,%u) "
20718  "(%lu values) do not match.",
20719  mp.imgin.pixel_type(),sizS,dx,dy,dz,dc,(ulongT)dx*dy*dz*dc);
20720  const CImg<doubleT> M(&_mp_arg(13) + 1,dx,dy,dz,(unsigned int)(sizM/(dx*dy*dz)),true);
20721  img.draw_image(x,y,z,c,S,M,opacity,(float)_mp_arg(15));
20722  } else img.draw_image(x,y,z,c,S,opacity);
20723  }
20724  return cimg::type<double>::nan();
20725  }
20726 
20727  static double mp_echo(_cimg_math_parser& mp) {
20728  const unsigned int nb_args = (unsigned int)(mp.opcode[2] - 3)/2;
20729  CImgList<charT> _str;
20730  CImg<charT> it;
20731  for (unsigned int n = 0; n<nb_args; ++n) {
20732  const unsigned int siz = (unsigned int)mp.opcode[4 + 2*n];
20733  if (siz) { // Vector argument -> string
20734  const double *ptr = &_mp_arg(3 + 2*n) + 1;
20735  unsigned int l = 0;
20736  while (l<siz && ptr[l]) ++l;
20737  CImg<doubleT>(ptr,l,1,1,1,true).move_to(_str);
20738  } else { // Scalar argument -> number
20739  it.assign(256);
20740  cimg_snprintf(it,it._width,"%.17g",_mp_arg(3 + 2*n));
20741  CImg<charT>::string(it,false,true).move_to(_str);
20742  }
20743  }
20744  CImg(1,1,1,1,0).move_to(_str);
20745  const CImg<charT> str = _str>'x';
20746  std::fprintf(cimg::output(),"\n%s",str._data);
20747  return cimg::type<double>::nan();
20748  }
20749 
20750  static double mp_eq(_cimg_math_parser& mp) {
20751  return (double)(_mp_arg(2)==_mp_arg(3));
20752  }
20753 
20754  static double mp_ext(_cimg_math_parser& mp) {
20755  const unsigned int nb_args = (unsigned int)(mp.opcode[2] - 3)/2;
20756  CImgList<charT> _str;
20757  CImg<charT> it;
20758  for (unsigned int n = 0; n<nb_args; ++n) {
20759  const unsigned int siz = (unsigned int)mp.opcode[4 + 2*n];
20760  if (siz) { // Vector argument -> string
20761  const double *ptr = &_mp_arg(3 + 2*n) + 1;
20762  unsigned int l = 0;
20763  while (l<siz && ptr[l]) ++l;
20764  CImg<doubleT>(ptr,l,1,1,1,true).move_to(_str);
20765  } else { // Scalar argument -> number
20766  it.assign(256);
20767  cimg_snprintf(it,it._width,"%.17g",_mp_arg(3 + 2*n));
20768  CImg<charT>::string(it,false,true).move_to(_str);
20769  }
20770  }
20771  CImg(1,1,1,1,0).move_to(_str);
20772  CImg<charT> str = _str>'x';
20773 #ifdef cimg_mp_ext_function
20774  cimg_mp_ext_function(str);
20775 #endif
20776  return cimg::type<double>::nan();
20777  }
20778 
20779  static double mp_exp(_cimg_math_parser& mp) {
20780  return std::exp(_mp_arg(2));
20781  }
20782 
20783  static double mp_eye(_cimg_math_parser& mp) {
20784  double *ptrd = &_mp_arg(1) + 1;
20785  const unsigned int k = (unsigned int)mp.opcode[2];
20786  CImg<doubleT>(ptrd,k,k,1,1,true).identity_matrix();
20787  return cimg::type<double>::nan();
20788  }
20789 
20790  static double mp_factorial(_cimg_math_parser& mp) {
20791  return cimg::factorial(_mp_arg(2));
20792  }
20793 
20794  static double mp_fibonacci(_cimg_math_parser& mp) {
20795  return cimg::fibonacci((int)_mp_arg(2));
20796  }
20797 
20798  static double mp_find(_cimg_math_parser& mp) {
20799  const bool is_forward = (bool)_mp_arg(5);
20800  const ulongT siz = (ulongT)mp.opcode[3];
20801  longT ind = (longT)(mp.opcode[6]!=_cimg_mp_slot_nan?_mp_arg(6):is_forward?0:siz - 1);
20802  if (ind<0 || ind>=(longT)siz) return -1.;
20803  const double
20804  *const ptrb = &_mp_arg(2) + 1,
20805  *const ptre = ptrb + siz,
20806  val = _mp_arg(4),
20807  *ptr = ptrb + ind;
20808 
20809  // Forward search
20810  if (is_forward) {
20811  while (ptr<ptre && *ptr!=val) ++ptr;
20812  return ptr==ptre?-1.:(double)(ptr - ptrb);
20813  }
20814 
20815  // Backward search.
20816  while (ptr>=ptrb && *ptr!=val) --ptr;
20817  return ptr<ptrb?-1.:(double)(ptr - ptrb);
20818  }
20819 
20820  static double mp_find_seq(_cimg_math_parser& mp) {
20821  const bool is_forward = (bool)_mp_arg(6);
20822  const ulongT
20823  siz1 = (ulongT)mp.opcode[3],
20824  siz2 = (ulongT)mp.opcode[5];
20825  longT ind = (longT)(mp.opcode[7]!=_cimg_mp_slot_nan?_mp_arg(7):is_forward?0:siz1 - 1);
20826  if (ind<0 || ind>=(longT)siz1) return -1.;
20827  const double
20828  *const ptr1b = &_mp_arg(2) + 1,
20829  *const ptr1e = ptr1b + siz1,
20830  *const ptr2b = &_mp_arg(4) + 1,
20831  *const ptr2e = ptr2b + siz2,
20832  *ptr1 = ptr1b + ind,
20833  *p1 = 0,
20834  *p2 = 0;
20835 
20836  // Forward search.
20837  if (is_forward) {
20838  do {
20839  while (ptr1<ptr1e && *ptr1!=*ptr2b) ++ptr1;
20840  p1 = ptr1 + 1;
20841  p2 = ptr2b + 1;
20842  while (p1<ptr1e && p2<ptr2e && *p1==*p2) { ++p1; ++p2; }
20843  } while (p2<ptr2e && ++ptr1<ptr1e);
20844  return p2<ptr2e?-1.0:(double)(ptr1 - ptr1b);
20845  }
20846 
20847  // Backward search.
20848  do {
20849  while (ptr1>=ptr1b && *ptr1!=*ptr2b) --ptr1;
20850  p1 = ptr1 + 1;
20851  p2 = ptr2b + 1;
20852  while (p1<ptr1e && p2<ptr2e && *p1==*p2) { ++p1; ++p2; }
20853  } while (p2<ptr2e && --ptr1>=ptr1b);
20854  return p2<ptr2e?-1.0:(double)(ptr1 - ptr1b);
20855  }
20856 
20857  static double mp_floor(_cimg_math_parser& mp) {
20858  return std::floor(_mp_arg(2));
20859  }
20860 
20861  static double mp_for(_cimg_math_parser& mp) {
20862  const ulongT
20863  mem_body = mp.opcode[1],
20864  mem_cond = mp.opcode[3];
20865  const CImg<ulongT>
20866  *const p_init = ++mp.p_code,
20867  *const p_cond = p_init + mp.opcode[4],
20868  *const p_body = p_cond + mp.opcode[5],
20869  *const p_post = p_body + mp.opcode[6],
20870  *const p_end = p_post + mp.opcode[7];
20871  const unsigned int vsiz = (unsigned int)mp.opcode[2];
20872  bool is_cond = false;
20873  if (mp.opcode[8]) { // Set default value for result and condition if necessary
20874  if (vsiz) CImg<doubleT>(&mp.mem[mem_body] + 1,vsiz,1,1,1,true).fill(cimg::type<double>::nan());
20875  else mp.mem[mem_body] = cimg::type<double>::nan();
20876  }
20877  if (mp.opcode[9]) mp.mem[mem_cond] = 0;
20878  const unsigned int _break_type = mp.break_type;
20879  mp.break_type = 0;
20880 
20881  for (mp.p_code = p_init; mp.p_code<p_cond; ++mp.p_code) { // Evaluate init
20882  mp.opcode._data = mp.p_code->_data;
20883  const ulongT target = mp.opcode[1];
20884  mp.mem[target] = _cimg_mp_defunc(mp);
20885  }
20886 
20887  if (!mp.break_type) do {
20888  for (mp.p_code = p_cond; mp.p_code<p_body; ++mp.p_code) { // Evaluate condition
20889  mp.opcode._data = mp.p_code->_data;
20890  const ulongT target = mp.opcode[1];
20891  mp.mem[target] = _cimg_mp_defunc(mp);
20892  }
20893  if (mp.break_type==1) break;
20894 
20895  is_cond = (bool)mp.mem[mem_cond];
20896  if (is_cond && !mp.break_type) {
20897  for (mp.p_code = p_body; mp.p_code<p_post; ++mp.p_code) { // Evaluate body
20898  mp.opcode._data = mp.p_code->_data;
20899  const ulongT target = mp.opcode[1];
20900  mp.mem[target] = _cimg_mp_defunc(mp);
20901  }
20902  if (mp.break_type==1) break; else if (mp.break_type==2) mp.break_type = 0;
20903 
20904  for (mp.p_code = p_post; mp.p_code<p_end; ++mp.p_code) { // Evaluate post-code
20905  mp.opcode._data = mp.p_code->_data;
20906  const ulongT target = mp.opcode[1];
20907  mp.mem[target] = _cimg_mp_defunc(mp);
20908  }
20909  if (mp.break_type==1) break; else if (mp.break_type==2) mp.break_type = 0;
20910  }
20911  } while (is_cond);
20912 
20913  mp.break_type = _break_type;
20914  mp.p_code = p_end - 1;
20915  return mp.mem[mem_body];
20916  }
20917 
20918  static double mp_fsize(_cimg_math_parser& mp) {
20919  const CImg<charT> filename(mp.opcode._data + 3,mp.opcode[2] - 3);
20920  return (double)cimg::fsize(filename);
20921  }
20922 
20923  static double mp_g(_cimg_math_parser& mp) {
20924  cimg::unused(mp);
20925  return cimg::grand();
20926  }
20927 
20928  static double mp_gauss(_cimg_math_parser& mp) {
20929  const double x = _mp_arg(2), s = _mp_arg(3);
20930  return std::exp(-x*x/(2*s*s))/std::sqrt(2*s*s*cimg::PI);
20931  }
20932 
20933  static double mp_gcd(_cimg_math_parser& mp) {
20934  return cimg::gcd((long)_mp_arg(2),(long)_mp_arg(3));
20935  }
20936 
20937  static double mp_gt(_cimg_math_parser& mp) {
20938  return (double)(_mp_arg(2)>_mp_arg(3));
20939  }
20940 
20941  static double mp_gte(_cimg_math_parser& mp) {
20942  return (double)(_mp_arg(2)>=_mp_arg(3));
20943  }
20944 
20945  static double mp_i(_cimg_math_parser& mp) {
20946  return (double)mp.imgin.atXYZC((int)mp.mem[_cimg_mp_slot_x],(int)mp.mem[_cimg_mp_slot_y],
20947  (int)mp.mem[_cimg_mp_slot_z],(int)mp.mem[_cimg_mp_slot_c],(T)0);
20948  }
20949 
20950  static double mp_if(_cimg_math_parser& mp) {
20951  const bool is_cond = (bool)_mp_arg(2);
20952  const ulongT
20953  mem_left = mp.opcode[3],
20954  mem_right = mp.opcode[4];
20955  const CImg<ulongT>
20956  *const p_right = ++mp.p_code + mp.opcode[5],
20957  *const p_end = p_right + mp.opcode[6];
20958  const unsigned int vtarget = (unsigned int)mp.opcode[1], vsiz = (unsigned int)mp.opcode[7];
20959  if (is_cond) for ( ; mp.p_code<p_right; ++mp.p_code) {
20960  mp.opcode._data = mp.p_code->_data;
20961  const ulongT target = mp.opcode[1];
20962  mp.mem[target] = _cimg_mp_defunc(mp);
20963  }
20964  else for (mp.p_code = p_right; mp.p_code<p_end; ++mp.p_code) {
20965  mp.opcode._data = mp.p_code->_data;
20966  const ulongT target = mp.opcode[1];
20967  mp.mem[target] = _cimg_mp_defunc(mp);
20968  }
20969  if (mp.p_code==mp.p_break) --mp.p_code;
20970  else mp.p_code = p_end - 1;
20971  if (vsiz) std::memcpy(&mp.mem[vtarget] + 1,&mp.mem[is_cond?mem_left:mem_right] + 1,sizeof(double)*vsiz);
20972  return mp.mem[is_cond?mem_left:mem_right];
20973  }
20974 
20975  static double mp_image_d(_cimg_math_parser& mp) {
20976  unsigned int ind = (unsigned int)mp.opcode[2];
20977  if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
20978  const CImg<T> &img = ind==~0U?mp.imgout:mp.listout[ind];
20979  return (double)img.depth();
20980  }
20981 
20982  static double mp_image_display(_cimg_math_parser& mp) {
20983  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listout.width());
20984  cimg::mutex(6);
20985  CImg<T> &img = mp.listout[ind];
20986  CImg<charT> title(256);
20987  std::fputc('\n',cimg::output());
20988  cimg_snprintf(title,title._width,"[ Image #%u ]",ind);
20989  img.display(title);
20990  cimg::mutex(6,0);
20991  return cimg::type<double>::nan();
20992  }
20993 
20994  static double mp_image_h(_cimg_math_parser& mp) {
20995  unsigned int ind = (unsigned int)mp.opcode[2];
20996  if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
20997  const CImg<T> &img = ind==~0U?mp.imgout:mp.listout[ind];
20998  return (double)img.height();
20999  }
21000 
21001  static double mp_image_median(_cimg_math_parser& mp) {
21002  unsigned int ind = (unsigned int)mp.opcode[2];
21003  if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21004  const CImg<T> &img = ind==~0U?mp.imgout:mp.listout[ind];
21005  return (double)img.median();
21006  }
21007 
21008  static double mp_image_print(_cimg_math_parser& mp) {
21009  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listout.width());
21010  cimg::mutex(6);
21011  CImg<T> &img = mp.listout[ind];
21012  CImg<charT> title(256);
21013  std::fputc('\n',cimg::output());
21014  cimg_snprintf(title,title._width,"[ Image #%u ]",ind);
21015  img.print(title);
21016  cimg::mutex(6,0);
21017  return cimg::type<double>::nan();
21018  }
21019 
21020  static double mp_image_resize(_cimg_math_parser& mp) {
21021  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listout.width());
21022  cimg::mutex(6);
21023  CImg<T> &img = mp.listout[ind];
21024  const double
21025  _w = mp.opcode[3]==~0U?-100:_mp_arg(3),
21026  _h = mp.opcode[4]==~0U?-100:_mp_arg(4),
21027  _d = mp.opcode[5]==~0U?-100:_mp_arg(5),
21028  _s = mp.opcode[6]==~0U?-100:_mp_arg(6);
21029  const unsigned int
21030  w = (unsigned int)(_w>=0?_w:-_w*img.width()/100),
21031  h = (unsigned int)(_h>=0?_h:-_h*img.height()/100),
21032  d = (unsigned int)(_d>=0?_d:-_d*img.depth()/100),
21033  s = (unsigned int)(_s>=0?_s:-_s*img.spectrum()/100),
21034  interp = (int)_mp_arg(7);
21035  if (mp.is_fill && img._data==mp.imgout._data) {
21036  cimg::mutex(6,0);
21037  throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'resize()': "
21038  "Cannot both fill and resize image (%u,%u,%u,%u) "
21039  "to new dimensions (%u,%u,%u,%u).",
21040  img.pixel_type(),img._width,img._height,img._depth,img._spectrum,w,h,d,s);
21041  }
21042  const unsigned int
21043  boundary = (int)_mp_arg(8);
21044  const float
21045  cx = (float)_mp_arg(9),
21046  cy = (float)_mp_arg(10),
21047  cz = (float)_mp_arg(11),
21048  cc = (float)_mp_arg(12);
21049  img.resize(w,h,d,s,interp,boundary,cx,cy,cz,cc);
21050  cimg::mutex(6,0);
21051  return cimg::type<double>::nan();
21052  }
21053 
21054  static double mp_image_s(_cimg_math_parser& mp) {
21055  unsigned int ind = (unsigned int)mp.opcode[2];
21056  if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21057  const CImg<T> &img = ind==~0U?mp.imgout:mp.listout[ind];
21058  return (double)img.spectrum();
21059  }
21060 
21061  static double mp_image_sort(_cimg_math_parser& mp) {
21062  const bool is_increasing = (bool)_mp_arg(3);
21063  const unsigned int
21064  ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listout.width()),
21065  axis = (unsigned int)_mp_arg(4);
21066  cimg::mutex(6);
21067  CImg<T> &img = mp.listout[ind];
21068  img.sort(is_increasing,
21069  axis==0 || axis=='x'?'x':
21070  axis==1 || axis=='y'?'y':
21071  axis==2 || axis=='z'?'z':
21072  axis==3 || axis=='c'?'c':0);
21073  cimg::mutex(6,0);
21074  return cimg::type<double>::nan();
21075  }
21076 
21077  static double mp_image_stats(_cimg_math_parser& mp) {
21078  double *ptrd = &_mp_arg(1) + 1;
21079  unsigned int ind = (unsigned int)mp.opcode[2];
21080  if (ind==~0U) CImg<doubleT>(ptrd,14,1,1,1,true) = mp.imgout.get_stats();
21081  else {
21082  ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21083  CImg<doubleT>(ptrd,14,1,1,1,true) = mp.listout[ind].get_stats();
21084  }
21085  return cimg::type<double>::nan();
21086  }
21087 
21088  static double mp_image_w(_cimg_math_parser& mp) {
21089  unsigned int ind = (unsigned int)mp.opcode[2];
21090  if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21091  const CImg<T> &img = ind==~0U?mp.imgout:mp.listout[ind];
21092  return (double)img.width();
21093  }
21094 
21095  static double mp_image_wh(_cimg_math_parser& mp) {
21096  unsigned int ind = (unsigned int)mp.opcode[2];
21097  if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21098  const CImg<T> &img = ind==~0U?mp.imgout:mp.listout[ind];
21099  return (double)img.width()*img.height();
21100  }
21101 
21102  static double mp_image_whd(_cimg_math_parser& mp) {
21103  unsigned int ind = (unsigned int)mp.opcode[2];
21104  if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21105  const CImg<T> &img = ind==~0U?mp.imgout:mp.listout[ind];
21106  return (double)img.width()*img.height()*img.depth();
21107  }
21108 
21109  static double mp_image_whds(_cimg_math_parser& mp) {
21110  unsigned int ind = (unsigned int)mp.opcode[2];
21111  if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21112  const CImg<T> &img = ind==~0U?mp.imgout:mp.listout[ind];
21113  return (double)img.width()*img.height()*img.depth()*img.spectrum();
21114  }
21115 
21116  static double mp_increment(_cimg_math_parser& mp) {
21117  return _mp_arg(2) + 1;
21118  }
21119 
21120  static double mp_int(_cimg_math_parser& mp) {
21121  return (double)(longT)_mp_arg(2);
21122  }
21123 
21124  static double mp_ioff(_cimg_math_parser& mp) {
21125  const unsigned int
21126  boundary_conditions = (unsigned int)_mp_arg(3);
21127  const CImg<T> &img = mp.imgin;
21128  const longT
21129  off = (longT)_mp_arg(2),
21130  whds = (longT)img.size();
21131  if (off>=0 && off<whds) return (double)img[off];
21132  if (img._data) switch (boundary_conditions) {
21133  case 3 : { // Mirror
21134  const longT whds2 = 2*whds, moff = cimg::mod(off,whds2);
21135  return (double)img[moff<whds?moff:whds2 - moff - 1];
21136  }
21137  case 2 : // Periodic
21138  return (double)img[cimg::mod(off,whds)];
21139  case 1 : // Neumann
21140  return (double)img[off<0?0:whds - 1];
21141  default : // Dirichlet
21142  return 0;
21143  }
21144  return 0;
21145  }
21146 
21147  static double mp_isbool(_cimg_math_parser& mp) {
21148  const double val = _mp_arg(2);
21149  return (double)(val==0.0 || val==1.0);
21150  }
21151 
21152  static double mp_isin(_cimg_math_parser& mp) {
21153  const unsigned int i_end = (unsigned int)mp.opcode[2];
21154  const double val = _mp_arg(3);
21155  for (unsigned int i = 4; i<i_end; ++i)
21156  if (val==_mp_arg(i)) return 1.0;
21157  return 0.0;
21158  }
21159 
21160  static double mp_isinf(_cimg_math_parser& mp) {
21161  return (double)cimg::type<double>::is_inf(_mp_arg(2));
21162  }
21163 
21164  static double mp_isint(_cimg_math_parser& mp) {
21165  return (double)(cimg::mod(_mp_arg(2),1.0)==0);
21166  }
21167 
21168  static double mp_isnan(_cimg_math_parser& mp) {
21169  return (double)cimg::type<double>::is_nan(_mp_arg(2));
21170  }
21171 
21172  static double mp_ixyzc(_cimg_math_parser& mp) {
21173  const unsigned int
21174  interpolation = (unsigned int)_mp_arg(6),
21175  boundary_conditions = (unsigned int)_mp_arg(7);
21176  const CImg<T> &img = mp.imgin;
21177  const double
21178  x = _mp_arg(2), y = _mp_arg(3),
21179  z = _mp_arg(4), c = _mp_arg(5);
21180  if (interpolation==0) switch (boundary_conditions) { // Nearest neighbor interpolation
21181  case 3 : { // Mirror
21182  const int
21183  w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(), s2 = 2*img.spectrum(),
21184  mx = cimg::mod((int)x,w2), my = cimg::mod((int)y,h2),
21185  mz = cimg::mod((int)z,d2), mc = cimg::mod((int)c,s2);
21186  return (double)img(mx<img.width()?mx:w2 - mx - 1,
21187  my<img.height()?my:h2 - my - 1,
21188  mz<img.depth()?mz:d2 - mz - 1,
21189  mc<img.spectrum()?mc:s2 - mc - 1);
21190  }
21191  case 2 : // Periodic
21192  return (double)img(cimg::mod((int)x,img.width()),
21193  cimg::mod((int)y,img.height()),
21194  cimg::mod((int)z,img.depth()),
21195  cimg::mod((int)c,img.spectrum()));
21196  case 1 : // Neumann
21197  return (double)img._atXYZC((int)x,(int)y,(int)z,(int)c);
21198  default : // Dirichlet
21199  return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,(T)0);
21200  } else switch (boundary_conditions) { // Linear interpolation
21201  case 3 : { // Mirror
21202  const float
21203  w2 = 2.0f*img.width(), h2 = 2.0f*img.height(), d2 = 2.0f*img.depth(), s2 = 2.0f*img.spectrum(),
21204  mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2),
21205  mz = cimg::mod((float)z,d2), mc = cimg::mod((float)c,s2);
21206  return (double)img._linear_atXYZC(mx<img.width()?mx:w2 - mx - 1,
21207  my<img.height()?my:h2 - my - 1,
21208  mz<img.depth()?mz:d2 - mz - 1,
21209  mc<img.spectrum()?mc:s2 - mc - 1);
21210  }
21211  case 2 : // Periodic
21212  return (double)img._linear_atXYZC(cimg::mod((float)x,(float)img.width()),
21213  cimg::mod((float)y,(float)img.height()),
21214  cimg::mod((float)z,(float)img.depth()),
21215  cimg::mod((float)c,(float)img.spectrum()));
21216  case 1 : // Neumann
21217  return (double)img._linear_atXYZC((float)x,(float)y,(float)z,(float)c);
21218  default : // Dirichlet
21219  return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,(T)0);
21220  }
21221  }
21222 
21223  static double mp_joff(_cimg_math_parser& mp) {
21224  const unsigned int
21225  boundary_conditions = (unsigned int)_mp_arg(3);
21226  const int
21227  ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y],
21228  oz = (int)mp.mem[_cimg_mp_slot_z], oc = (int)mp.mem[_cimg_mp_slot_c];
21229  const CImg<T> &img = mp.imgin;
21230  const longT
21231  off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(2),
21232  whds = (longT)img.size();
21233  if (off>=0 && off<whds) return (double)img[off];
21234  if (img._data) switch (boundary_conditions) {
21235  case 3 : { // Mirror
21236  const longT whds2 = 2*whds, moff = cimg::mod(off,whds2);
21237  return (double)img[moff<whds?moff:whds2 - moff - 1];
21238  }
21239  case 2 : // Periodic
21240  return (double)img[cimg::mod(off,whds)];
21241  case 1 : // Neumann
21242  return (double)img[off<0?0:whds - 1];
21243  default : // Dirichlet
21244  return 0;
21245  }
21246  return 0;
21247  }
21248 
21249  static double mp_jxyzc(_cimg_math_parser& mp) {
21250  const unsigned int
21251  interpolation = (unsigned int)_mp_arg(6),
21252  boundary_conditions = (unsigned int)_mp_arg(7);
21253  const CImg<T> &img = mp.imgin;
21254  const double
21255  ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y],
21256  oz = mp.mem[_cimg_mp_slot_z], oc = mp.mem[_cimg_mp_slot_c],
21257  x = ox + _mp_arg(2), y = oy + _mp_arg(3),
21258  z = oz + _mp_arg(4), c = oc + _mp_arg(5);
21259  if (interpolation==0) switch (boundary_conditions) { // Nearest neighbor interpolation
21260  case 3 : { // Mirror
21261  const int
21262  w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(), s2 = 2*img.spectrum(),
21263  mx = cimg::mod((int)x,w2), my = cimg::mod((int)y,h2),
21264  mz = cimg::mod((int)z,d2), mc = cimg::mod((int)c,s2);
21265  return (double)img(mx<img.width()?mx:w2 - mx - 1,
21266  my<img.height()?my:h2 - my - 1,
21267  mz<img.depth()?mz:d2 - mz - 1,
21268  mc<img.spectrum()?mc:s2 - mc - 1);
21269  }
21270  case 2 : // Periodic
21271  return (double)img(cimg::mod((int)x,img.width()),
21272  cimg::mod((int)y,img.height()),
21273  cimg::mod((int)z,img.depth()),
21274  cimg::mod((int)c,img.spectrum()));
21275  case 1 : // Neumann
21276  return (double)img._atXYZC((int)x,(int)y,(int)z,(int)c);
21277  default : // Dirichlet
21278  return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,(T)0);
21279  } else switch (boundary_conditions) { // Linear interpolation
21280  case 3 : { // Mirror
21281  const float
21282  w2 = 2.0f*img.width(), h2 = 2.0f*img.height(), d2 = 2.0f*img.depth(), s2 = 2.0f*img.spectrum(),
21283  mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2),
21284  mz = cimg::mod((float)z,d2), mc = cimg::mod((float)c,s2);
21285  return (double)img._linear_atXYZC(mx<img.width()?mx:w2 - mx - 1,
21286  my<img.height()?my:h2 - my - 1,
21287  mz<img.depth()?mz:d2 - mz - 1,
21288  mc<img.spectrum()?mc:s2 - mc - 1);
21289  }
21290  case 2 : // Periodic
21291  return (double)img._linear_atXYZC(cimg::mod((float)x,(float)img.width()),
21292  cimg::mod((float)y,(float)img.height()),
21293  cimg::mod((float)z,(float)img.depth()),
21294  cimg::mod((float)c,(float)img.spectrum()));
21295  case 1 : // Neumann
21296  return (double)img._linear_atXYZC((float)x,(float)y,(float)z,(float)c);
21297  default : // Dirichlet
21298  return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,(T)0);
21299  }
21300  }
21301 
21302  static double mp_kth(_cimg_math_parser& mp) {
21303  const unsigned int i_end = (unsigned int)mp.opcode[2];
21304  CImg<doubleT> vals(i_end - 4);
21305  double *p = vals.data();
21306  for (unsigned int i = 4; i<i_end; ++i) *(p++) = _mp_arg(i);
21307  int ind = (int)cimg::round(_mp_arg(3));
21308  if (ind<0) ind+=vals.width() + 1;
21309  ind = std::max(1,std::min(vals.width(),ind));
21310  return vals.kth_smallest(ind - 1);
21311  }
21312 
21313  static double mp_linear_add(_cimg_math_parser& mp) {
21314  return _mp_arg(2)*_mp_arg(3) + _mp_arg(4);
21315  }
21316 
21317  static double mp_linear_sub_left(_cimg_math_parser& mp) {
21318  return _mp_arg(2)*_mp_arg(3) - _mp_arg(4);
21319  }
21320 
21321  static double mp_linear_sub_right(_cimg_math_parser& mp) {
21322  return _mp_arg(4) - _mp_arg(2)*_mp_arg(3);
21323  }
21324 
21325  static double mp_list_depth(_cimg_math_parser& mp) {
21326  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21327  return (double)mp.listin[ind]._depth;
21328  }
21329 
21330  static double mp_list_find(_cimg_math_parser& mp) {
21331  const unsigned int
21332  indi = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21333  const CImg<T> &img = mp.listin[indi];
21334  const bool is_forward = (bool)_mp_arg(4);
21335  const ulongT siz = (ulongT)img.size();
21336  longT ind = (longT)(mp.opcode[5]!=_cimg_mp_slot_nan?_mp_arg(5):is_forward?0:siz - 1);
21337  if (ind<0 || ind>=(longT)siz) return -1.;
21338  const T
21339  *const ptrb = img.data(),
21340  *const ptre = img.end(),
21341  *ptr = ptrb + ind;
21342  const double val = _mp_arg(3);
21343 
21344  // Forward search
21345  if (is_forward) {
21346  while (ptr<ptre && (double)*ptr!=val) ++ptr;
21347  return ptr==ptre?-1.:(double)(ptr - ptrb);
21348  }
21349 
21350  // Backward search.
21351  while (ptr>=ptrb && (double)*ptr!=val) --ptr;
21352  return ptr<ptrb?-1.:(double)(ptr - ptrb);
21353  }
21354 
21355  static double mp_list_find_seq(_cimg_math_parser& mp) {
21356  const unsigned int
21357  indi = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21358  const CImg<T> &img = mp.listin[indi];
21359  const bool is_forward = (bool)_mp_arg(5);
21360  const ulongT
21361  siz1 = (ulongT)img.size(),
21362  siz2 = (ulongT)mp.opcode[4];
21363  longT ind = (longT)(mp.opcode[6]!=_cimg_mp_slot_nan?_mp_arg(6):is_forward?0:siz1 - 1);
21364  if (ind<0 || ind>=(longT)siz1) return -1.;
21365  const T
21366  *const ptr1b = img.data(),
21367  *const ptr1e = ptr1b + siz1,
21368  *ptr1 = ptr1b + ind,
21369  *p1 = 0;
21370  const double
21371  *const ptr2b = &_mp_arg(3) + 1,
21372  *const ptr2e = ptr2b + siz2,
21373  *p2 = 0;
21374 
21375  // Forward search.
21376  if (is_forward) {
21377  do {
21378  while (ptr1<ptr1e && *ptr1!=*ptr2b) ++ptr1;
21379  p1 = ptr1 + 1;
21380  p2 = ptr2b + 1;
21381  while (p1<ptr1e && p2<ptr2e && *p1==*p2) { ++p1; ++p2; }
21382  } while (p2<ptr2e && ++ptr1<ptr1e);
21383  return p2<ptr2e?-1.0:(double)(ptr1 - ptr1b);
21384  }
21385 
21386  // Backward search.
21387  do {
21388  while (ptr1>=ptr1b && *ptr1!=*ptr2b) --ptr1;
21389  p1 = ptr1 + 1;
21390  p2 = ptr2b + 1;
21391  while (p1<ptr1e && p2<ptr2e && *p1==*p2) { ++p1; ++p2; }
21392  } while (p2<ptr2e && --ptr1>=ptr1b);
21393  return p2<ptr2e?-1.0:(double)(ptr1 - ptr1b);
21394  }
21395 
21396  static double mp_list_height(_cimg_math_parser& mp) {
21397  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21398  return (double)mp.listin[ind]._height;
21399  }
21400 
21401  static double mp_list_ioff(_cimg_math_parser& mp) {
21402  const unsigned int
21403  ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
21404  boundary_conditions = (unsigned int)_mp_arg(4);
21405  const CImg<T> &img = mp.listin[ind];
21406  const longT
21407  off = (longT)_mp_arg(3),
21408  whds = (longT)img.size();
21409  if (off>=0 && off<whds) return (double)img[off];
21410  if (img._data) switch (boundary_conditions) {
21411  case 3 : { // Mirror
21412  const longT whds2 = 2*whds, moff = cimg::mod(off,whds2);
21413  return (double)img[moff<whds?moff:whds2 - moff - 1];
21414  }
21415  case 2 : // Periodic
21416  return (double)img[cimg::mod(off,whds)];
21417  case 1 : // Neumann
21418  return (double)img[off<0?0:whds - 1];
21419  default : // Dirichlet
21420  return 0;
21421  }
21422  return 0;
21423  }
21424 
21425  static double mp_list_is_shared(_cimg_math_parser& mp) {
21426  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21427  return (double)mp.listin[ind]._is_shared;
21428  }
21429 
21430  static double mp_list_ixyzc(_cimg_math_parser& mp) {
21431  const unsigned int
21432  ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
21433  interpolation = (unsigned int)_mp_arg(7),
21434  boundary_conditions = (unsigned int)_mp_arg(8);
21435  const CImg<T> &img = mp.listin[ind];
21436  const double
21437  x = _mp_arg(3), y = _mp_arg(4),
21438  z = _mp_arg(5), c = _mp_arg(6);
21439  if (interpolation==0) switch (boundary_conditions) { // Nearest neighbor interpolation
21440  case 3 : { // Mirror
21441  const int
21442  w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(), s2 = 2*img.spectrum(),
21443  mx = cimg::mod((int)x,w2), my = cimg::mod((int)y,h2),
21444  mz = cimg::mod((int)z,d2), mc = cimg::mod((int)c,s2);
21445  return (double)img(mx<img.width()?mx:w2 - mx - 1,
21446  my<img.height()?my:h2 - my - 1,
21447  mz<img.depth()?mz:d2 - mz - 1,
21448  mc<img.spectrum()?mc:s2 - mc - 1);
21449  }
21450  case 2 : // Periodic
21451  return (double)img(cimg::mod((int)x,img.width()),
21452  cimg::mod((int)y,img.height()),
21453  cimg::mod((int)z,img.depth()),
21454  cimg::mod((int)c,img.spectrum()));
21455  case 1 : // Neumann
21456  return (double)img._atXYZC((int)x,(int)y,(int)z,(int)c);
21457  default : // Dirichlet
21458  return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,(T)0);
21459  } else switch (boundary_conditions) { // Linear interpolation
21460  case 3 : { // Mirror
21461  const float
21462  w2 = 2.0f*img.width(), h2 = 2.0f*img.height(), d2 = 2.0f*img.depth(), s2 = 2.0f*img.spectrum(),
21463  mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2),
21464  mz = cimg::mod((float)z,d2), mc = cimg::mod((float)c,s2);
21465  return (double)img._linear_atXYZC(mx<img.width()?mx:w2 - mx - 1,
21466  my<img.height()?my:h2 - my - 1,
21467  mz<img.depth()?mz:d2 - mz - 1,
21468  mc<img.spectrum()?mc:s2 - mc - 1);
21469  }
21470  case 2 : // Periodic
21471  return (double)img._linear_atXYZC(cimg::mod((float)x,(float)img.width()),
21472  cimg::mod((float)y,(float)img.height()),
21473  cimg::mod((float)z,(float)img.depth()),
21474  cimg::mod((float)c,(float)img.spectrum()));
21475  case 1 : // Neumann
21476  return (double)img._linear_atXYZC((float)x,(float)y,(float)z,(float)c);
21477  default : // Dirichlet
21478  return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,(T)0);
21479  }
21480  }
21481 
21482  static double mp_list_joff(_cimg_math_parser& mp) {
21483  const unsigned int
21484  ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
21485  boundary_conditions = (unsigned int)_mp_arg(4);
21486  const int
21487  ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y],
21488  oz = (int)mp.mem[_cimg_mp_slot_z], oc = (int)mp.mem[_cimg_mp_slot_c];
21489  const CImg<T> &img = mp.listin[ind];
21490  const longT
21491  off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(3),
21492  whds = (longT)img.size();
21493  if (off>=0 && off<whds) return (double)img[off];
21494  if (img._data) switch (boundary_conditions) {
21495  case 3 : { // Mirror
21496  const longT whds2 = 2*whds, moff = cimg::mod(off,whds2);
21497  return (double)img[moff<whds?moff:whds2 - moff - 1];
21498  }
21499  case 2 : // Periodic
21500  return (double)img[cimg::mod(off,whds)];
21501  case 1 : // Neumann
21502  return (double)img[off<0?0:whds - 1];
21503  default : // Dirichlet
21504  return 0;
21505  }
21506  return 0;
21507  }
21508 
21509  static double mp_list_jxyzc(_cimg_math_parser& mp) {
21510  const unsigned int
21511  ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
21512  interpolation = (unsigned int)_mp_arg(7),
21513  boundary_conditions = (unsigned int)_mp_arg(8);
21514  const CImg<T> &img = mp.listin[ind];
21515  const double
21516  ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y],
21517  oz = mp.mem[_cimg_mp_slot_z], oc = mp.mem[_cimg_mp_slot_c],
21518  x = ox + _mp_arg(3), y = oy + _mp_arg(4),
21519  z = oz + _mp_arg(5), c = oc + _mp_arg(6);
21520  if (interpolation==0) switch (boundary_conditions) { // Nearest neighbor interpolation
21521  case 3 : { // Mirror
21522  const int
21523  w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(), s2 = 2*img.spectrum(),
21524  mx = cimg::mod((int)x,w2), my = cimg::mod((int)y,h2),
21525  mz = cimg::mod((int)z,d2), mc = cimg::mod((int)c,s2);
21526  return (double)img(mx<img.width()?mx:w2 - mx - 1,
21527  my<img.height()?my:h2 - my - 1,
21528  mz<img.depth()?mz:d2 - mz - 1,
21529  mc<img.spectrum()?mc:s2 - mc - 1);
21530  }
21531  case 2 : // Periodic
21532  return (double)img(cimg::mod((int)x,img.width()),
21533  cimg::mod((int)y,img.height()),
21534  cimg::mod((int)z,img.depth()),
21535  cimg::mod((int)c,img.spectrum()));
21536  case 1 : // Neumann
21537  return (double)img._atXYZC((int)x,(int)y,(int)z,(int)c);
21538  default : // Dirichlet
21539  return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,(T)0);
21540  } else switch (boundary_conditions) { // Linear interpolation
21541  case 3 : { // Mirror
21542  const float
21543  w2 = 2.0f*img.width(), h2 = 2.0f*img.height(), d2 = 2.0f*img.depth(), s2 = 2.0f*img.spectrum(),
21544  mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2),
21545  mz = cimg::mod((float)z,d2), mc = cimg::mod((float)c,s2);
21546  return (double)img._linear_atXYZC(mx<img.width()?mx:w2 - mx - 1,
21547  my<img.height()?my:h2 - my - 1,
21548  mz<img.depth()?mz:d2 - mz - 1,
21549  mc<img.spectrum()?mc:s2 - mc - 1);
21550  }
21551  case 2 : // Periodic
21552  return (double)img._linear_atXYZC(cimg::mod((float)x,(float)img.width()),
21553  cimg::mod((float)y,(float)img.height()),
21554  cimg::mod((float)z,(float)img.depth()),
21555  cimg::mod((float)c,(float)img.spectrum()));
21556  case 1 : // Neumann
21557  return (double)img._linear_atXYZC((float)x,(float)y,(float)z,(float)c);
21558  default : // Dirichlet
21559  return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,(T)0);
21560  }
21561  }
21562 
21563  static double mp_list_l(_cimg_math_parser& mp) {
21564  return (double)mp.listout.width();
21565  }
21566 
21567  static double mp_list_median(_cimg_math_parser& mp) {
21568  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21569  if (!mp.list_median) mp.list_median.assign(mp.listin._width);
21570  if (!mp.list_median[ind]) CImg<doubleT>::vector(mp.listin[ind].median()).move_to(mp.list_median[ind]);
21571  return *mp.list_median[ind];
21572  }
21573 
21574  static double mp_list_set_ioff(_cimg_math_parser& mp) {
21575  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21576  CImg<T> &img = mp.listout[ind];
21577  const longT
21578  off = (longT)_mp_arg(3),
21579  whds = (longT)img.size();
21580  const double val = _mp_arg(1);
21581  if (off>=0 && off<whds) img[off] = (T)val;
21582  return val;
21583  }
21584 
21585  static double mp_list_set_ixyzc(_cimg_math_parser& mp) {
21586  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21587  CImg<T> &img = mp.listout[ind];
21588  const int
21589  x = (int)_mp_arg(3), y = (int)_mp_arg(4),
21590  z = (int)_mp_arg(5), c = (int)_mp_arg(6);
21591  const double val = _mp_arg(1);
21592  if (x>=0 && x<img.width() && y>=0 && y<img.height() &&
21593  z>=0 && z<img.depth() && c>=0 && c<img.spectrum())
21594  img(x,y,z,c) = (T)val;
21595  return val;
21596  }
21597 
21598  static double mp_list_set_joff(_cimg_math_parser& mp) {
21599  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21600  CImg<T> &img = mp.listout[ind];
21601  const int
21602  ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y],
21603  oz = (int)mp.mem[_cimg_mp_slot_z], oc = (int)mp.mem[_cimg_mp_slot_c];
21604  const longT
21605  off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(3),
21606  whds = (longT)img.size();
21607  const double val = _mp_arg(1);
21608  if (off>=0 && off<whds) img[off] = (T)val;
21609  return val;
21610  }
21611 
21612  static double mp_list_set_jxyzc(_cimg_math_parser& mp) {
21613  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21614  CImg<T> &img = mp.listout[ind];
21615  const double
21616  ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y],
21617  oz = mp.mem[_cimg_mp_slot_z], oc = mp.mem[_cimg_mp_slot_c];
21618  const int
21619  x = (int)(ox + _mp_arg(3)), y = (int)(oy + _mp_arg(4)),
21620  z = (int)(oz + _mp_arg(5)), c = (int)(oc + _mp_arg(6));
21621  const double val = _mp_arg(1);
21622  if (x>=0 && x<img.width() && y>=0 && y<img.height() &&
21623  z>=0 && z<img.depth() && c>=0 && c<img.spectrum())
21624  img(x,y,z,c) = (T)val;
21625  return val;
21626  }
21627 
21628  static double mp_list_set_Ioff_s(_cimg_math_parser& mp) {
21629  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21630  CImg<T> &img = mp.listout[ind];
21631  const longT
21632  off = (longT)_mp_arg(3),
21633  whd = (longT)img.width()*img.height()*img.depth();
21634  const T val = (T)_mp_arg(1);
21635  if (off>=0 && off<whd) {
21636  T *ptrd = &img[off];
21637  cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
21638  }
21639  return _mp_arg(1);
21640  }
21641 
21642  static double mp_list_set_Ioff_v(_cimg_math_parser& mp) {
21643  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21644  CImg<T> &img = mp.listout[ind];
21645  const longT
21646  off = (longT)_mp_arg(3),
21647  whd = (longT)img.width()*img.height()*img.depth();
21648  const double *ptrs = &_mp_arg(1) + 1;
21649  if (off>=0 && off<whd) {
21650  const unsigned int vsiz = (unsigned int)mp.opcode[4];
21651  T *ptrd = &img[off];
21652  cimg_for_inC(img,0,vsiz - 1,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
21653  }
21654  return cimg::type<double>::nan();
21655  }
21656 
21657  static double mp_list_set_Ixyz_s(_cimg_math_parser& mp) {
21658  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21659  CImg<T> &img = mp.listout[ind];
21660  const int
21661  x = (int)_mp_arg(3),
21662  y = (int)_mp_arg(4),
21663  z = (int)_mp_arg(5);
21664  const T val = (T)_mp_arg(1);
21665  if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
21666  T *ptrd = &img(x,y,z);
21667  const ulongT whd = (ulongT)img._width*img._height*img._depth;
21668  cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
21669  }
21670  return _mp_arg(1);
21671  }
21672 
21673  static double mp_list_set_Ixyz_v(_cimg_math_parser& mp) {
21674  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21675  CImg<T> &img = mp.listout[ind];
21676  const int
21677  x = (int)_mp_arg(3),
21678  y = (int)_mp_arg(4),
21679  z = (int)_mp_arg(5);
21680  const double *ptrs = &_mp_arg(1) + 1;
21681  if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
21682  const unsigned int vsiz = (unsigned int)mp.opcode[6];
21683  T *ptrd = &img(x,y,z);
21684  const ulongT whd = (ulongT)img._width*img._height*img._depth;
21685  cimg_for_inC(img,0,vsiz - 1,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
21686  }
21687  return cimg::type<double>::nan();
21688  }
21689 
21690  static double mp_list_set_Joff_s(_cimg_math_parser& mp) {
21691  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21692  CImg<T> &img = mp.listout[ind];
21693  const int
21694  ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y],
21695  oz = (int)mp.mem[_cimg_mp_slot_z], oc = (int)mp.mem[_cimg_mp_slot_c];
21696  const longT
21697  off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(3),
21698  whd = (longT)img.width()*img.height()*img.depth();
21699  const T val = (T)_mp_arg(1);
21700  if (off>=0 && off<whd) {
21701  T *ptrd = &img[off];
21702  cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
21703  }
21704  return _mp_arg(1);
21705  }
21706 
21707  static double mp_list_set_Joff_v(_cimg_math_parser& mp) {
21708  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21709  CImg<T> &img = mp.listout[ind];
21710  const int
21711  ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y],
21712  oz = (int)mp.mem[_cimg_mp_slot_z], oc = (int)mp.mem[_cimg_mp_slot_c];
21713  const longT
21714  off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(3),
21715  whd = (longT)img.width()*img.height()*img.depth();
21716  const double *ptrs = &_mp_arg(1) + 1;
21717  if (off>=0 && off<whd) {
21718  const unsigned int vsiz = (unsigned int)mp.opcode[4];
21719  T *ptrd = &img[off];
21720  cimg_for_inC(img,0,vsiz - 1,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
21721  }
21722  return cimg::type<double>::nan();
21723  }
21724 
21725  static double mp_list_set_Jxyz_s(_cimg_math_parser& mp) {
21726  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21727  CImg<T> &img = mp.listout[ind];
21728  const double ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], oz = mp.mem[_cimg_mp_slot_z];
21729  const int
21730  x = (int)(ox + _mp_arg(3)),
21731  y = (int)(oy + _mp_arg(4)),
21732  z = (int)(oz + _mp_arg(5));
21733  const T val = (T)_mp_arg(1);
21734  if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
21735  T *ptrd = &img(x,y,z);
21736  const ulongT whd = (ulongT)img._width*img._height*img._depth;
21737  cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
21738  }
21739  return _mp_arg(1);
21740  }
21741 
21742  static double mp_list_set_Jxyz_v(_cimg_math_parser& mp) {
21743  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21744  CImg<T> &img = mp.listout[ind];
21745  const double ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], oz = mp.mem[_cimg_mp_slot_z];
21746  const int
21747  x = (int)(ox + _mp_arg(3)),
21748  y = (int)(oy + _mp_arg(4)),
21749  z = (int)(oz + _mp_arg(5));
21750  const double *ptrs = &_mp_arg(1) + 1;
21751  if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
21752  const unsigned int vsiz = (unsigned int)mp.opcode[6];
21753  T *ptrd = &img(x,y,z);
21754  const ulongT whd = (ulongT)img._width*img._height*img._depth;
21755  cimg_for_inC(img,0,vsiz - 1,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
21756  }
21757  return cimg::type<double>::nan();
21758  }
21759 
21760  static double mp_list_spectrum(_cimg_math_parser& mp) {
21761  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21762  return (double)mp.listin[ind]._spectrum;
21763  }
21764 
21765  static double mp_list_stats(_cimg_math_parser& mp) {
21766  const unsigned int
21767  ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
21768  k = (unsigned int)mp.opcode[3];
21769  if (!mp.list_stats) mp.list_stats.assign(mp.listin._width);
21770  if (!mp.list_stats[ind]) mp.list_stats[ind].assign(1,14,1,1,0).fill(mp.listin[ind].get_stats(),false);
21771  return mp.list_stats(ind,k);
21772  }
21773 
21774  static double mp_list_wh(_cimg_math_parser& mp) {
21775  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21776  return (double)mp.listin[ind]._width*mp.listin[ind]._height;
21777  }
21778 
21779  static double mp_list_whd(_cimg_math_parser& mp) {
21780  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21781  return (double)mp.listin[ind]._width*mp.listin[ind]._height*mp.listin[ind]._depth;
21782  }
21783 
21784  static double mp_list_whds(_cimg_math_parser& mp) {
21785  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21786  return (double)mp.listin[ind]._width*mp.listin[ind]._height*mp.listin[ind]._depth*mp.listin[ind]._spectrum;
21787  }
21788 
21789  static double mp_list_width(_cimg_math_parser& mp) {
21790  const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
21791  return (double)mp.listin[ind]._width;
21792  }
21793 
21794  static double mp_list_Ioff(_cimg_math_parser& mp) {
21795  double *ptrd = &_mp_arg(1) + 1;
21796  const unsigned int
21797  ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
21798  boundary_conditions = (unsigned int)_mp_arg(4),
21799  vsiz = (unsigned int)mp.opcode[5];
21800  const CImg<T> &img = mp.listin[ind];
21801  const longT
21802  off = (longT)_mp_arg(3),
21803  whd = (longT)img.width()*img.height()*img.depth();
21804  const T *ptrs;
21805  if (off>=0 && off<whd) {
21806  ptrs = &img[off];
21807  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
21808  return cimg::type<double>::nan();
21809  }
21810  if (img._data) switch (boundary_conditions) {
21811  case 3 : { // Mirror
21812  const longT whd2 = 2*whd, moff = cimg::mod(off,whd2);
21813  ptrs = &img[moff<whd?moff:whd2 - moff - 1];
21814  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
21815  return cimg::type<double>::nan();
21816  }
21817  case 2 : // Periodic
21818  ptrs = &img[cimg::mod(off,whd)];
21819  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
21820  return cimg::type<double>::nan();
21821  case 1 : // Neumann
21822  ptrs = off<0?&img[0]:&img[whd - 1];
21823  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
21824  return cimg::type<double>::nan();
21825  default : // Dirichlet
21826  std::memset(ptrd,0,vsiz*sizeof(double));
21827  return cimg::type<double>::nan();
21828  }
21829  std::memset(ptrd,0,vsiz*sizeof(double));
21830  return cimg::type<double>::nan();
21831  }
21832 
21833  static double mp_list_Ixyz(_cimg_math_parser& mp) {
21834  double *ptrd = &_mp_arg(1) + 1;
21835  const unsigned int
21836  ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
21837  interpolation = (unsigned int)_mp_arg(6),
21838  boundary_conditions = (unsigned int)_mp_arg(7),
21839  vsiz = (unsigned int)mp.opcode[8];
21840  const CImg<T> &img = mp.listin[ind];
21841  const double x = _mp_arg(3), y = _mp_arg(4), z = _mp_arg(5);
21842  const ulongT whd = (ulongT)img._width*img._height*img._depth;
21843  const T *ptrs;
21844  if (interpolation==0) switch (boundary_conditions) { // Nearest neighbor interpolation
21845  case 3 : { // Mirror
21846  const int
21847  w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(),
21848  mx = cimg::mod((int)x,w2), my = cimg::mod((int)y,h2), mz = cimg::mod((int)z,d2),
21849  cx = mx<img.width()?mx:w2 - mx - 1,
21850  cy = my<img.height()?my:h2 - my - 1,
21851  cz = mz<img.depth()?mz:d2 - mz - 1;
21852  ptrs = &img(cx,cy,cz);
21853  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
21854  } break;
21855  case 2 : { // Periodic
21856  const int
21857  cx = cimg::mod((int)x,img.width()),
21858  cy = cimg::mod((int)y,img.height()),
21859  cz = cimg::mod((int)z,img.depth());
21860  ptrs = &img(cx,cy,cz);
21861  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
21862  } break;
21863  case 1 : { // Neumann
21864  ptrs = &img._atXYZ((int)x,(int)y,(int)z);
21865  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
21866  } break;
21867  default : // Dirichlet
21868  if (img.containsXYZC(x,y,z)) {
21869  ptrs = &img((int)x,(int)y,(int)z);
21870  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
21871  } else std::memset(ptrd,0,vsiz*sizeof(double));
21872  } else switch (boundary_conditions) { // Linear interpolation
21873  case 3 : { // Mirror
21874  const float
21875  w2 = 2.0f*img.width(), h2 = 2.0f*img.height(), d2 = 2.0f*img.depth(),
21876  mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), mz = cimg::mod((float)z,d2),
21877  cx = mx<img.width()?mx:w2 - mx - 1,
21878  cy = my<img.height()?my:h2 - my - 1,
21879  cz = mz<img.depth()?mz:d2 - mz - 1;
21880  cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ(cx,cy,cz,c);
21881  } break;
21882  case 2 : { // Periodic
21883  const float
21884  cx = cimg::mod((float)x,(float)img.width()),
21885  cy = cimg::mod((float)y,(float)img.height()),
21886  cz = cimg::mod((float)z,(float)img.depth());
21887  cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ(cx,cy,cz,c);
21888  } break;
21889  case 1 : // Neumann
21890  cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ((float)x,(float)y,(float)z,c);
21891  break;
21892  case 0 : // Dirichlet
21893  cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,(T)0);
21894  }
21895  return cimg::type<double>::nan();
21896  }
21897 
21898  static double mp_list_Joff(_cimg_math_parser& mp) {
21899  double *ptrd = &_mp_arg(1) + 1;
21900  const unsigned int
21901  ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
21902  boundary_conditions = (unsigned int)_mp_arg(4),
21903  vsiz = (unsigned int)mp.opcode[5];
21904  const int
21905  ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y], oz = (int)mp.mem[_cimg_mp_slot_z];
21906  const CImg<T> &img = mp.listin[ind];
21907  const longT
21908  off = img.offset(ox,oy,oz) + (longT)_mp_arg(3),
21909  whd = (longT)img.width()*img.height()*img.depth();
21910  const T *ptrs;
21911  if (off>=0 && off<whd) {
21912  ptrs = &img[off];
21913  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
21914  return cimg::type<double>::nan();
21915  }
21916  if (img._data) switch (boundary_conditions) {
21917  case 3 : { // Mirror
21918  const longT whd2 = 2*whd, moff = cimg::mod(off,whd2);
21919  ptrs = &img[moff<whd?moff:whd2 - moff - 1];
21920  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
21921  return cimg::type<double>::nan();
21922  }
21923  case 2 : // Periodic
21924  ptrs = &img[cimg::mod(off,whd)];
21925  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
21926  return cimg::type<double>::nan();
21927  case 1 : // Neumann
21928  ptrs = off<0?&img[0]:&img[whd - 1];
21929  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
21930  return cimg::type<double>::nan();
21931  default : // Dirichlet
21932  std::memset(ptrd,0,vsiz*sizeof(double));
21933  return cimg::type<double>::nan();
21934  }
21935  std::memset(ptrd,0,vsiz*sizeof(double));
21936  return cimg::type<double>::nan();
21937  }
21938 
21939  static double mp_list_Jxyz(_cimg_math_parser& mp) {
21940  double *ptrd = &_mp_arg(1) + 1;
21941  const unsigned int
21942  ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
21943  interpolation = (unsigned int)_mp_arg(6),
21944  boundary_conditions = (unsigned int)_mp_arg(7),
21945  vsiz = (unsigned int)mp.opcode[8];
21946  const CImg<T> &img = mp.listin[ind];
21947  const double
21948  ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], oz = mp.mem[_cimg_mp_slot_z],
21949  x = ox + _mp_arg(3), y = oy + _mp_arg(4), z = oz + _mp_arg(5);
21950  const ulongT whd = (ulongT)img._width*img._height*img._depth;
21951  const T *ptrs;
21952  if (interpolation==0) switch (boundary_conditions) { // Nearest neighbor interpolation
21953  case 3 : { // Mirror
21954  const int
21955  w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(),
21956  mx = cimg::mod((int)x,w2), my = cimg::mod((int)y,h2), mz = cimg::mod((int)z,d2),
21957  cx = mx<img.width()?mx:w2 - mx - 1,
21958  cy = my<img.height()?my:h2 - my - 1,
21959  cz = mz<img.depth()?mz:d2 - mz - 1;
21960  ptrs = &img(cx,cy,cz);
21961  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
21962  } break;
21963  case 2 : { // Periodic
21964  const int
21965  cx = cimg::mod((int)x,img.width()),
21966  cy = cimg::mod((int)y,img.height()),
21967  cz = cimg::mod((int)z,img.depth());
21968  ptrs = &img(cx,cy,cz);
21969  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
21970  } break;
21971  case 1 : { // Neumann
21972  ptrs = &img._atXYZ((int)x,(int)y,(int)z);
21973  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
21974  } break;
21975  default : // Dirichlet
21976  if (img.containsXYZC(x,y,z)) {
21977  ptrs = &img((int)x,(int)y,(int)z);
21978  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
21979  } else std::memset(ptrd,0,vsiz*sizeof(double));
21980  } else switch (boundary_conditions) { // Linear interpolation
21981  case 3 : { // Mirror
21982  const float
21983  w2 = 2.0f*img.width(), h2 = 2.0f*img.height(), d2 = 2.0f*img.depth(),
21984  mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), mz = cimg::mod((float)z,d2),
21985  cx = mx<img.width()?mx:w2 - mx - 1,
21986  cy = my<img.height()?my:h2 - my - 1,
21987  cz = mz<img.depth()?mz:d2 - mz - 1;
21988  cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ(cx,cy,cz,c);
21989  } break;
21990  case 2 : { // Periodic
21991  const float
21992  cx = cimg::mod((float)x,(float)img.width()),
21993  cy = cimg::mod((float)y,(float)img.height()),
21994  cz = cimg::mod((float)z,(float)img.depth());
21995  cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ(cx,cy,cz,c);
21996  } break;
21997  case 1 : // Neumann
21998  cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ((float)x,(float)y,(float)z,c);
21999  break;
22000  default : // Dirichlet
22001  cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,(T)0);
22002  }
22003  return cimg::type<double>::nan();
22004  }
22005 
22006  static double mp_log(_cimg_math_parser& mp) {
22007  return std::log(_mp_arg(2));
22008  }
22009 
22010  static double mp_log10(_cimg_math_parser& mp) {
22011  return std::log10(_mp_arg(2));
22012  }
22013 
22014  static double mp_log2(_cimg_math_parser& mp) {
22015  return cimg::log2(_mp_arg(2));
22016  }
22017 
22018  static double mp_logical_and(_cimg_math_parser& mp) {
22019  const bool val_left = (bool)_mp_arg(2);
22020  const CImg<ulongT> *const p_end = ++mp.p_code + mp.opcode[4];
22021  if (!val_left) { mp.p_code = p_end - 1; return 0; }
22022  const ulongT mem_right = mp.opcode[3];
22023  for ( ; mp.p_code<p_end; ++mp.p_code) {
22024  mp.opcode._data = mp.p_code->_data;
22025  const ulongT target = mp.opcode[1];
22026  mp.mem[target] = _cimg_mp_defunc(mp);
22027  }
22028  --mp.p_code;
22029  return (double)(bool)mp.mem[mem_right];
22030  }
22031 
22032  static double mp_logical_not(_cimg_math_parser& mp) {
22033  return (double)!_mp_arg(2);
22034  }
22035 
22036  static double mp_logical_or(_cimg_math_parser& mp) {
22037  const bool val_left = (bool)_mp_arg(2);
22038  const CImg<ulongT> *const p_end = ++mp.p_code + mp.opcode[4];
22039  if (val_left) { mp.p_code = p_end - 1; return 1; }
22040  const ulongT mem_right = mp.opcode[3];
22041  for ( ; mp.p_code<p_end; ++mp.p_code) {
22042  mp.opcode._data = mp.p_code->_data;
22043  const ulongT target = mp.opcode[1];
22044  mp.mem[target] = _cimg_mp_defunc(mp);
22045  }
22046  --mp.p_code;
22047  return (double)(bool)mp.mem[mem_right];
22048  }
22049 
22050  static double mp_lowercase(_cimg_math_parser& mp) {
22051  return cimg::lowercase(_mp_arg(2));
22052  }
22053 
22054  static double mp_lt(_cimg_math_parser& mp) {
22055  return (double)(_mp_arg(2)<_mp_arg(3));
22056  }
22057 
22058  static double mp_lte(_cimg_math_parser& mp) {
22059  return (double)(_mp_arg(2)<=_mp_arg(3));
22060  }
22061 
22062  static double mp_matrix_eig(_cimg_math_parser& mp) {
22063  double *ptrd = &_mp_arg(1) + 1;
22064  const double *ptr1 = &_mp_arg(2) + 1;
22065  const unsigned int k = (unsigned int)mp.opcode[3];
22066  CImg<doubleT> val, vec;
22067  CImg<doubleT>(ptr1,k,k,1,1,true).symmetric_eigen(val,vec);
22068  CImg<doubleT>(ptrd,1,k,1,1,true) = val;
22069  CImg<doubleT>(ptrd + k,k,k,1,1,true) = vec.get_transpose();
22070  return cimg::type<double>::nan();
22071  }
22072 
22073  static double mp_matrix_inv(_cimg_math_parser& mp) {
22074  double *ptrd = &_mp_arg(1) + 1;
22075  const double *ptr1 = &_mp_arg(2) + 1;
22076  const unsigned int k = (unsigned int)mp.opcode[3];
22077  CImg<doubleT>(ptrd,k,k,1,1,true) = CImg<doubleT>(ptr1,k,k,1,1,true).get_invert();
22078  return cimg::type<double>::nan();
22079  }
22080 
22081  static double mp_matrix_mul(_cimg_math_parser& mp) {
22082  double *ptrd = &_mp_arg(1) + 1;
22083  const double
22084  *ptr1 = &_mp_arg(2) + 1,
22085  *ptr2 = &_mp_arg(3) + 1;
22086  const unsigned int
22087  k = (unsigned int)mp.opcode[4],
22088  l = (unsigned int)mp.opcode[5],
22089  m = (unsigned int)mp.opcode[6];
22090  CImg<doubleT>(ptrd,m,k,1,1,true) = CImg<doubleT>(ptr1,l,k,1,1,true)*CImg<doubleT>(ptr2,m,l,1,1,true);
22091  return cimg::type<double>::nan();
22092  }
22093 
22094  static double mp_matrix_pseudoinv(_cimg_math_parser& mp) {
22095  double *ptrd = &_mp_arg(1) + 1;
22096  const double *ptr1 = &_mp_arg(2) + 1;
22097  const unsigned int
22098  k = (unsigned int)mp.opcode[3],
22099  l = (unsigned int)mp.opcode[4];
22100  CImg<doubleT>(ptrd,l,k,1,1,true) = CImg<doubleT>(ptr1,k,l,1,1,true).get_pseudoinvert();
22101  return cimg::type<double>::nan();
22102  }
22103 
22104  static double mp_matrix_svd(_cimg_math_parser& mp) {
22105  double *ptrd = &_mp_arg(1) + 1;
22106  const double *ptr1 = &_mp_arg(2) + 1;
22107  const unsigned int
22108  k = (unsigned int)mp.opcode[3],
22109  l = (unsigned int)mp.opcode[4];
22110  CImg<doubleT> U, S, V;
22111  CImg<doubleT>(ptr1,k,l,1,1,true).SVD(U,S,V);
22112  CImg<doubleT>(ptrd,k,l,1,1,true) = U;
22113  CImg<doubleT>(ptrd + k*l,1,k,1,1,true) = S;
22114  CImg<doubleT>(ptrd + k*l + k,k,k,1,1,true) = V;
22115  return cimg::type<double>::nan();
22116  }
22117 
22118  static double mp_max(_cimg_math_parser& mp) {
22119  const unsigned int i_end = (unsigned int)mp.opcode[2];
22120  double val = _mp_arg(3);
22121  for (unsigned int i = 4; i<i_end; ++i) val = std::max(val,_mp_arg(i));
22122  return val;
22123  }
22124 
22125  static double* _mp_memcopy_double(_cimg_math_parser& mp, const unsigned int ind, const ulongT *const p_ref,
22126  const longT siz, const long inc) {
22127  const longT
22128  off = *p_ref?p_ref[1] + (longT)mp.mem[(longT)p_ref[2]] + 1:ind,
22129  eoff = off + (siz - 1)*inc;
22130  if (off<0 || eoff>=mp.mem.width())
22131  throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'copy()': "
22132  "Out-of-bounds variable pointer "
22133  "(length: %ld, increment: %ld, offset start: %ld, "
22134  "offset end: %ld, offset max: %u).",
22135  mp.imgin.pixel_type(),siz,inc,off,eoff,mp.mem._width - 1);
22136  return &mp.mem[off];
22137  }
22138 
22139  static float* _mp_memcopy_float(_cimg_math_parser& mp, const ulongT *const p_ref,
22140  const longT siz, const long inc) {
22141  const unsigned ind = (unsigned int)p_ref[1];
22142  const CImg<T> &img = ind==~0U?mp.imgin:mp.listin[cimg::mod((int)mp.mem[ind],mp.listin.width())];
22143  const bool is_relative = (bool)p_ref[2];
22144  int ox, oy, oz, oc;
22145  longT off = 0;
22146  if (is_relative) {
22147  ox = (int)mp.mem[_cimg_mp_slot_x];
22148  oy = (int)mp.mem[_cimg_mp_slot_y];
22149  oz = (int)mp.mem[_cimg_mp_slot_z];
22150  oc = (int)mp.mem[_cimg_mp_slot_c];
22151  off = img.offset(ox,oy,oz,oc);
22152  }
22153  if ((*p_ref)%2) {
22154  const int
22155  x = (int)mp.mem[p_ref[3]],
22156  y = (int)mp.mem[p_ref[4]],
22157  z = (int)mp.mem[p_ref[5]],
22158  c = *p_ref==5?0:(int)mp.mem[p_ref[6]];
22159  off+=img.offset(x,y,z,c);
22160  } else off+=(longT)mp.mem[p_ref[3]];
22161  const longT eoff = off + (siz - 1)*inc;
22162  if (off<0 || eoff>=(longT)img.size())
22163  throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'copy()': "
22164  "Out-of-bounds image pointer "
22165  "(length: %ld, increment: %ld, offset start: %ld, "
22166  "offset end: %ld, offset max: %lu).",
22167  mp.imgin.pixel_type(),siz,inc,off,eoff,img.size() - 1);
22168  return (float*)&img[off];
22169  }
22170 
22171  static double mp_memcopy(_cimg_math_parser& mp) {
22172  longT siz = (longT)_mp_arg(4);
22173  const longT inc_d = (longT)_mp_arg(5), inc_s = (longT)_mp_arg(6);
22174  const float
22175  _opacity = (float)_mp_arg(7),
22176  opacity = (float)cimg::abs(_opacity),
22177  omopacity = 1 - std::max(_opacity,0.0f);
22178  if (siz>0) {
22179  const bool
22180  is_doubled = mp.opcode[8]<=1,
22181  is_doubles = mp.opcode[15]<=1;
22182  if (is_doubled && is_doubles) { // (double*) <- (double*)
22183  double *ptrd = _mp_memcopy_double(mp,(unsigned int)mp.opcode[2],&mp.opcode[8],siz,inc_d);
22184  const double *ptrs = _mp_memcopy_double(mp,(unsigned int)mp.opcode[3],&mp.opcode[15],siz,inc_s);
22185  if (inc_d==1 && inc_s==1 && _opacity>=1) {
22186  if (ptrs + siz - 1<ptrd || ptrs>ptrd + siz - 1) std::memcpy(ptrd,ptrs,siz*sizeof(double));
22187  else std::memmove(ptrd,ptrs,siz*sizeof(double));
22188  } else {
22189  if (ptrs + (siz - 1)*inc_s<ptrd || ptrs>ptrd + (siz - 1)*inc_d) {
22190  if (_opacity>=1) while (siz-->0) { *ptrd = *ptrs; ptrd+=inc_d; ptrs+=inc_s; }
22191  else while (siz-->0) { *ptrd = omopacity**ptrd + opacity**ptrs; ptrd+=inc_d; ptrs+=inc_s; }
22192  } else { // Overlapping buffers
22193  CImg<doubleT> buf((unsigned int)siz);
22194  cimg_for(buf,ptr,double) { *ptr = *ptrs; ptrs+=inc_s; }
22195  ptrs = buf;
22196  if (_opacity>=1) while (siz-->0) { *ptrd = *(ptrs++); ptrd+=inc_d; }
22197  else while (siz-->0) { *ptrd = omopacity**ptrd + opacity**(ptrs++); ptrd+=inc_d; }
22198  }
22199  }
22200  } else if (is_doubled && !is_doubles) { // (double*) <- (float*)
22201  double *ptrd = _mp_memcopy_double(mp,(unsigned int)mp.opcode[2],&mp.opcode[8],siz,inc_d);
22202  const float *ptrs = _mp_memcopy_float(mp,&mp.opcode[15],siz,inc_s);
22203  if (_opacity>=1) while (siz-->0) { *ptrd = *ptrs; ptrd+=inc_d; ptrs+=inc_s; }
22204  else while (siz-->0) { *ptrd = omopacity**ptrd + _opacity**ptrs; ptrd+=inc_d; ptrs+=inc_s; }
22205  } else if (!is_doubled && is_doubles) { // (float*) <- (double*)
22206  float *ptrd = _mp_memcopy_float(mp,&mp.opcode[8],siz,inc_d);
22207  const double *ptrs = _mp_memcopy_double(mp,(unsigned int)mp.opcode[3],&mp.opcode[15],siz,inc_s);
22208  if (_opacity>=1) while (siz-->0) { *ptrd = (float)*ptrs; ptrd+=inc_d; ptrs+=inc_s; }
22209  else while (siz-->0) { *ptrd = (float)(omopacity**ptrd + opacity**ptrs); ptrd+=inc_d; ptrs+=inc_s; }
22210  } else { // (float*) <- (float*)
22211  float *ptrd = _mp_memcopy_float(mp,&mp.opcode[8],siz,inc_d);
22212  const float *ptrs = _mp_memcopy_float(mp,&mp.opcode[15],siz,inc_s);
22213  if (inc_d==1 && inc_s==1 && _opacity>=1) {
22214  if (ptrs + siz - 1<ptrd || ptrs>ptrd + siz - 1) std::memcpy(ptrd,ptrs,siz*sizeof(float));
22215  else std::memmove(ptrd,ptrs,siz*sizeof(float));
22216  } else {
22217  if (ptrs + (siz - 1)*inc_s<ptrd || ptrs>ptrd + (siz - 1)*inc_d) {
22218  if (_opacity>=1) while (siz-->0) { *ptrd = *ptrs; ptrd+=inc_d; ptrs+=inc_s; }
22219  else while (siz-->0) { *ptrd = omopacity**ptrd + opacity**ptrs; ptrd+=inc_d; ptrs+=inc_s; }
22220  } else { // Overlapping buffers
22221  CImg<floatT> buf((unsigned int)siz);
22222  cimg_for(buf,ptr,float) { *ptr = *ptrs; ptrs+=inc_s; }
22223  ptrs = buf;
22224  if (_opacity>=1) while (siz-->0) { *ptrd = *(ptrs++); ptrd+=inc_d; }
22225  else while (siz-->0) { *ptrd = omopacity**ptrd + opacity**(ptrs++); ptrd+=inc_d; }
22226  }
22227  }
22228  }
22229  }
22230  return _mp_arg(1);
22231  }
22232 
22233  static double mp_min(_cimg_math_parser& mp) {
22234  const unsigned int i_end = (unsigned int)mp.opcode[2];
22235  double val = _mp_arg(3);
22236  for (unsigned int i = 4; i<i_end; ++i) val = std::min(val,_mp_arg(i));
22237  return val;
22238  }
22239 
22240  static double mp_minus(_cimg_math_parser& mp) {
22241  return -_mp_arg(2);
22242  }
22243 
22244  static double mp_mean(_cimg_math_parser& mp) {
22245  const unsigned int i_end = (unsigned int)mp.opcode[2];
22246  double val = _mp_arg(3);
22247  for (unsigned int i = 4; i<i_end; ++i) val+=_mp_arg(i);
22248  return val/(i_end - 3);
22249  }
22250 
22251  static double mp_median(_cimg_math_parser& mp) {
22252  const unsigned int i_end = (unsigned int)mp.opcode[2];
22253  switch (i_end - 3) {
22254  case 1 : return _mp_arg(3);
22255  case 2 : return cimg::median(_mp_arg(3),_mp_arg(4));
22256  case 3 : return cimg::median(_mp_arg(3),_mp_arg(4),_mp_arg(5));
22257  case 5 : return cimg::median(_mp_arg(3),_mp_arg(4),_mp_arg(5),_mp_arg(6),_mp_arg(7));
22258  case 7 : return cimg::median(_mp_arg(3),_mp_arg(4),_mp_arg(5),_mp_arg(6),_mp_arg(7),_mp_arg(8),_mp_arg(9));
22259  case 9 : return cimg::median(_mp_arg(3),_mp_arg(4),_mp_arg(5),_mp_arg(6),_mp_arg(7),_mp_arg(8),_mp_arg(9),
22260  _mp_arg(10),_mp_arg(11));
22261  case 13 : return cimg::median(_mp_arg(3),_mp_arg(4),_mp_arg(5),_mp_arg(6),_mp_arg(7),_mp_arg(8),_mp_arg(9),
22262  _mp_arg(10),_mp_arg(11),_mp_arg(12),_mp_arg(13),_mp_arg(14),_mp_arg(15));
22263  }
22264  CImg<doubleT> vals(i_end - 3);
22265  double *p = vals.data();
22266  for (unsigned int i = 3; i<i_end; ++i) *(p++) = _mp_arg(i);
22267  return vals.median();
22268  }
22269 
22270  static double mp_modulo(_cimg_math_parser& mp) {
22271  return cimg::mod(_mp_arg(2),_mp_arg(3));
22272  }
22273 
22274  static double mp_mul(_cimg_math_parser& mp) {
22275  return _mp_arg(2)*_mp_arg(3);
22276  }
22277 
22278  static double mp_mul2(_cimg_math_parser& mp) {
22279  return _mp_arg(2)*_mp_arg(3)*_mp_arg(4);
22280  }
22281 
22282  static double mp_neq(_cimg_math_parser& mp) {
22283  return (double)(_mp_arg(2)!=_mp_arg(3));
22284  }
22285 
22286  static double mp_norm0(_cimg_math_parser& mp) {
22287  const unsigned int i_end = (unsigned int)mp.opcode[2];
22288  switch (i_end - 3) {
22289  case 1 : return _mp_arg(3)!=0;
22290  case 2 : return (_mp_arg(3)!=0) + (_mp_arg(4)!=0);
22291  }
22292  double res = 0;
22293  for (unsigned int i = 3; i<i_end; ++i)
22294  res+=_mp_arg(i)==0?0:1;
22295  return res;
22296  }
22297 
22298  static double mp_norm1(_cimg_math_parser& mp) {
22299  const unsigned int i_end = (unsigned int)mp.opcode[2];
22300  switch (i_end - 3) {
22301  case 1 : return cimg::abs(_mp_arg(3));
22302  case 2 : return cimg::abs(_mp_arg(3)) + cimg::abs(_mp_arg(4));
22303  }
22304  double res = 0;
22305  for (unsigned int i = 3; i<i_end; ++i)
22306  res+=cimg::abs(_mp_arg(i));
22307  return res;
22308  }
22309 
22310  static double mp_norm2(_cimg_math_parser& mp) {
22311  const unsigned int i_end = (unsigned int)mp.opcode[2];
22312  switch (i_end - 3) {
22313  case 1 : return cimg::abs(_mp_arg(3));
22314  case 2 : return cimg::_hypot(_mp_arg(3),_mp_arg(4));
22315  }
22316  double res = 0;
22317  for (unsigned int i = 3; i<i_end; ++i)
22318  res+=cimg::sqr(_mp_arg(i));
22319  return std::sqrt(res);
22320  }
22321 
22322  static double mp_norminf(_cimg_math_parser& mp) {
22323  const unsigned int i_end = (unsigned int)mp.opcode[2];
22324  switch (i_end - 3) {
22325  case 1 : return cimg::abs(_mp_arg(3));
22326  case 2 : return std::max(cimg::abs(_mp_arg(3)),cimg::abs(_mp_arg(4)));
22327  }
22328  double res = 0;
22329  for (unsigned int i = 3; i<i_end; ++i) {
22330  const double val = cimg::abs(_mp_arg(i));
22331  if (val>res) res = val;
22332  }
22333  return res;
22334  }
22335 
22336  static double mp_normp(_cimg_math_parser& mp) {
22337  const unsigned int i_end = (unsigned int)mp.opcode[2];
22338  if (i_end==4) return cimg::abs(_mp_arg(3));
22339  const double p = (double)mp.opcode[3];
22340  double res = 0;
22341  for (unsigned int i = 4; i<i_end; ++i)
22342  res+=std::pow(cimg::abs(_mp_arg(i)),p);
22343  res = std::pow(res,1/p);
22344  return res>0?res:0.0;
22345  }
22346 
22347  static double mp_permutations(_cimg_math_parser& mp) {
22348  return cimg::permutations(_mp_arg(2),_mp_arg(3),(bool)_mp_arg(4));
22349  }
22350 
22351  static double mp_pow(_cimg_math_parser& mp) {
22352  const double v = _mp_arg(2), p = _mp_arg(3);
22353  return std::pow(v,p);
22354  }
22355 
22356  static double mp_pow0_25(_cimg_math_parser& mp) {
22357  const double val = _mp_arg(2);
22358  return std::sqrt(std::sqrt(val));
22359  }
22360 
22361  static double mp_pow3(_cimg_math_parser& mp) {
22362  const double val = _mp_arg(2);
22363  return val*val*val;
22364  }
22365 
22366  static double mp_pow4(_cimg_math_parser& mp) {
22367  const double val = _mp_arg(2);
22368  return val*val*val*val;
22369  }
22370 
22371  static double mp_print(_cimg_math_parser& mp) {
22372  const double val = _mp_arg(1);
22373  const bool print_char = (bool)mp.opcode[3];
22374  cimg_pragma_openmp(critical(mp_print))
22375  {
22376  CImg<charT> expr(mp.opcode[2] - 4);
22377  const ulongT *ptrs = mp.opcode._data + 4;
22378  cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++);
22379  cimg::strellipsize(expr);
22380  cimg::mutex(6);
22381  if (print_char)
22382  std::fprintf(cimg::output(),"\n[" cimg_appname "_math_parser] %s = %g = '%c'",expr._data,val,(int)val);
22383  else
22384  std::fprintf(cimg::output(),"\n[" cimg_appname "_math_parser] %s = %g",expr._data,val);
22385  std::fflush(cimg::output());
22386  cimg::mutex(6,0);
22387  }
22388  return val;
22389  }
22390 
22391  static double mp_prod(_cimg_math_parser& mp) {
22392  const unsigned int i_end = (unsigned int)mp.opcode[2];
22393  double val = _mp_arg(3);
22394  for (unsigned int i = 4; i<i_end; ++i) val*=_mp_arg(i);
22395  return val;
22396  }
22397 
22398  static double mp_copy(_cimg_math_parser& mp) {
22399  return _mp_arg(2);
22400  }
22401 
22402  static double mp_rol(_cimg_math_parser& mp) {
22403  return cimg::rol(_mp_arg(2),(unsigned int)_mp_arg(3));
22404  }
22405 
22406  static double mp_ror(_cimg_math_parser& mp) {
22407  return cimg::ror(_mp_arg(2),(unsigned int)_mp_arg(3));
22408  }
22409 
22410  static double mp_rot2d(_cimg_math_parser& mp) {
22411  double *ptrd = &_mp_arg(1) + 1;
22412  const float
22413  theta = (float)_mp_arg(2)*cimg::PI/180,
22414  ca = std::cos(theta),
22415  sa = std::sin(theta);
22416  *(ptrd++) = ca;
22417  *(ptrd++) = -sa;
22418  *(ptrd++) = sa;
22419  *ptrd = ca;
22420  return cimg::type<double>::nan();
22421  }
22422 
22423  static double mp_rot3d(_cimg_math_parser& mp) {
22424  double *ptrd = &_mp_arg(1) + 1;
22425  const float x = (float)_mp_arg(2), y = (float)_mp_arg(3), z = (float)_mp_arg(4), theta = (float)_mp_arg(5);
22426  CImg<doubleT>(ptrd,3,3,1,1,true) = CImg<doubleT>::rotation_matrix(x,y,z,theta);
22427  return cimg::type<double>::nan();
22428  }
22429 
22430  static double mp_round(_cimg_math_parser& mp) {
22431  return cimg::round(_mp_arg(2),_mp_arg(3),(int)_mp_arg(4));
22432  }
22433 
22434  static double mp_self_add(_cimg_math_parser& mp) {
22435  return _mp_arg(1)+=_mp_arg(2);
22436  }
22437 
22438  static double mp_self_bitwise_and(_cimg_math_parser& mp) {
22439  double &val = _mp_arg(1);
22440  return val = (double)((longT)val & (longT)_mp_arg(2));
22441  }
22442 
22443  static double mp_self_bitwise_left_shift(_cimg_math_parser& mp) {
22444  double &val = _mp_arg(1);
22445  return val = (double)((longT)val<<(unsigned int)_mp_arg(2));
22446  }
22447 
22448  static double mp_self_bitwise_or(_cimg_math_parser& mp) {
22449  double &val = _mp_arg(1);
22450  return val = (double)((longT)val | (longT)_mp_arg(2));
22451  }
22452 
22453  static double mp_self_bitwise_right_shift(_cimg_math_parser& mp) {
22454  double &val = _mp_arg(1);
22455  return val = (double)((longT)val>>(unsigned int)_mp_arg(2));
22456  }
22457 
22458  static double mp_self_decrement(_cimg_math_parser& mp) {
22459  return --_mp_arg(1);
22460  }
22461 
22462  static double mp_self_increment(_cimg_math_parser& mp) {
22463  return ++_mp_arg(1);
22464  }
22465 
22466  static double mp_self_map_vector_s(_cimg_math_parser& mp) { // Vector += scalar
22467  unsigned int
22468  ptrd = (unsigned int)mp.opcode[1] + 1,
22469  siz = (unsigned int)mp.opcode[2];
22470  mp_func op = (mp_func)mp.opcode[3];
22471  CImg<ulongT> l_opcode(1,3);
22472  l_opcode[2] = mp.opcode[4]; // Scalar argument.
22473  l_opcode.swap(mp.opcode);
22474  ulongT &target = mp.opcode[1];
22475  while (siz-->0) { target = ptrd++; (*op)(mp); }
22476  l_opcode.swap(mp.opcode);
22477  return cimg::type<double>::nan();
22478  }
22479 
22480  static double mp_self_map_vector_v(_cimg_math_parser& mp) { // Vector += vector
22481  unsigned int
22482  ptrd = (unsigned int)mp.opcode[1] + 1,
22483  siz = (unsigned int)mp.opcode[2],
22484  ptrs = (unsigned int)mp.opcode[4] + 1;
22485  mp_func op = (mp_func)mp.opcode[3];
22486  CImg<ulongT> l_opcode(1,4);
22487  l_opcode.swap(mp.opcode);
22488  ulongT &target = mp.opcode[1], &argument = mp.opcode[2];
22489  while (siz-->0) { target = ptrd++; argument = ptrs++; (*op)(mp); }
22490  l_opcode.swap(mp.opcode);
22491  return cimg::type<double>::nan();
22492  }
22493 
22494  static double mp_self_mul(_cimg_math_parser& mp) {
22495  return _mp_arg(1)*=_mp_arg(2);
22496  }
22497 
22498  static double mp_self_div(_cimg_math_parser& mp) {
22499  return _mp_arg(1)/=_mp_arg(2);
22500  }
22501 
22502  static double mp_self_modulo(_cimg_math_parser& mp) {
22503  double &val = _mp_arg(1);
22504  return val = cimg::mod(val,_mp_arg(2));
22505  }
22506 
22507  static double mp_self_pow(_cimg_math_parser& mp) {
22508  double &val = _mp_arg(1);
22509  return val = std::pow(val,_mp_arg(2));
22510  }
22511 
22512  static double mp_self_sub(_cimg_math_parser& mp) {
22513  return _mp_arg(1)-=_mp_arg(2);
22514  }
22515 
22516  static double mp_set_ioff(_cimg_math_parser& mp) {
22517  CImg<T> &img = mp.imgout;
22518  const longT
22519  off = (longT)_mp_arg(2),
22520  whds = (longT)img.size();
22521  const double val = _mp_arg(1);
22522  if (off>=0 && off<whds) img[off] = (T)val;
22523  return val;
22524  }
22525 
22526  static double mp_set_ixyzc(_cimg_math_parser& mp) {
22527  CImg<T> &img = mp.imgout;
22528  const int
22529  x = (int)_mp_arg(2), y = (int)_mp_arg(3),
22530  z = (int)_mp_arg(4), c = (int)_mp_arg(5);
22531  const double val = _mp_arg(1);
22532  if (x>=0 && x<img.width() && y>=0 && y<img.height() &&
22533  z>=0 && z<img.depth() && c>=0 && c<img.spectrum())
22534  img(x,y,z,c) = (T)val;
22535  return val;
22536  }
22537 
22538  static double mp_set_joff(_cimg_math_parser& mp) {
22539  CImg<T> &img = mp.imgout;
22540  const int
22541  ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y],
22542  oz = (int)mp.mem[_cimg_mp_slot_z], oc = (int)mp.mem[_cimg_mp_slot_c];
22543  const longT
22544  off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(2),
22545  whds = (longT)img.size();
22546  const double val = _mp_arg(1);
22547  if (off>=0 && off<whds) img[off] = (T)val;
22548  return val;
22549  }
22550 
22551  static double mp_set_jxyzc(_cimg_math_parser& mp) {
22552  CImg<T> &img = mp.imgout;
22553  const double
22554  ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y],
22555  oz = mp.mem[_cimg_mp_slot_z], oc = mp.mem[_cimg_mp_slot_c];
22556  const int
22557  x = (int)(ox + _mp_arg(2)), y = (int)(oy + _mp_arg(3)),
22558  z = (int)(oz + _mp_arg(4)), c = (int)(oc + _mp_arg(5));
22559  const double val = _mp_arg(1);
22560  if (x>=0 && x<img.width() && y>=0 && y<img.height() &&
22561  z>=0 && z<img.depth() && c>=0 && c<img.spectrum())
22562  img(x,y,z,c) = (T)val;
22563  return val;
22564  }
22565 
22566  static double mp_set_Ioff_s(_cimg_math_parser& mp) {
22567  CImg<T> &img = mp.imgout;
22568  const longT
22569  off = (longT)_mp_arg(2),
22570  whd = (longT)img.width()*img.height()*img.depth();
22571  const T val = (T)_mp_arg(1);
22572  if (off>=0 && off<whd) {
22573  T *ptrd = &img[off];
22574  cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
22575  }
22576  return _mp_arg(1);
22577  }
22578 
22579  static double mp_set_Ioff_v(_cimg_math_parser& mp) {
22580  CImg<T> &img = mp.imgout;
22581  const longT
22582  off = (longT)_mp_arg(2),
22583  whd = (longT)img.width()*img.height()*img.depth();
22584  const double *ptrs = &_mp_arg(1) + 1;
22585  if (off>=0 && off<whd) {
22586  const unsigned int vsiz = (unsigned int)mp.opcode[3];
22587  T *ptrd = &img[off];
22588  cimg_for_inC(img,0,vsiz - 1,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
22589  }
22590  return cimg::type<double>::nan();
22591  }
22592 
22593  static double mp_set_Ixyz_s(_cimg_math_parser& mp) {
22594  CImg<T> &img = mp.imgout;
22595  const int
22596  x = (int)_mp_arg(2),
22597  y = (int)_mp_arg(3),
22598  z = (int)_mp_arg(4);
22599  const T val = (T)_mp_arg(1);
22600  if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
22601  T *ptrd = &img(x,y,z);
22602  const ulongT whd = (ulongT)img._width*img._height*img._depth;
22603  cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
22604  }
22605  return _mp_arg(1);
22606  }
22607 
22608  static double mp_set_Ixyz_v(_cimg_math_parser& mp) {
22609  CImg<T> &img = mp.imgout;
22610  const int
22611  x = (int)_mp_arg(2),
22612  y = (int)_mp_arg(3),
22613  z = (int)_mp_arg(4);
22614  const double *ptrs = &_mp_arg(1) + 1;
22615  if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
22616  const unsigned int vsiz = (unsigned int)mp.opcode[5];
22617  T *ptrd = &img(x,y,z);
22618  const ulongT whd = (ulongT)img._width*img._height*img._depth;
22619  cimg_for_inC(img,0,vsiz - 1,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
22620  }
22621  return cimg::type<double>::nan();
22622  }
22623 
22624  static double mp_set_Joff_s(_cimg_math_parser& mp) {
22625  CImg<T> &img = mp.imgout;
22626  const int
22627  ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y],
22628  oz = (int)mp.mem[_cimg_mp_slot_z], oc = (int)mp.mem[_cimg_mp_slot_c];
22629  const longT
22630  off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(2),
22631  whd = (longT)img.width()*img.height()*img.depth();
22632  const T val = (T)_mp_arg(1);
22633  if (off>=0 && off<whd) {
22634  T *ptrd = &img[off];
22635  cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
22636  }
22637  return _mp_arg(1);
22638  }
22639 
22640  static double mp_set_Joff_v(_cimg_math_parser& mp) {
22641  CImg<T> &img = mp.imgout;
22642  const int
22643  ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y],
22644  oz = (int)mp.mem[_cimg_mp_slot_z], oc = (int)mp.mem[_cimg_mp_slot_c];
22645  const longT
22646  off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(2),
22647  whd = (longT)img.width()*img.height()*img.depth();
22648  const double *ptrs = &_mp_arg(1) + 1;
22649  if (off>=0 && off<whd) {
22650  const unsigned int vsiz = (unsigned int)mp.opcode[3];
22651  T *ptrd = &img[off];
22652  cimg_for_inC(img,0,vsiz - 1,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
22653  }
22654  return cimg::type<double>::nan();
22655  }
22656 
22657  static double mp_set_Jxyz_s(_cimg_math_parser& mp) {
22658  CImg<T> &img = mp.imgout;
22659  const double ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], oz = mp.mem[_cimg_mp_slot_z];
22660  const int
22661  x = (int)(ox + _mp_arg(2)),
22662  y = (int)(oy + _mp_arg(3)),
22663  z = (int)(oz + _mp_arg(4));
22664  const T val = (T)_mp_arg(1);
22665  if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
22666  T *ptrd = &img(x,y,z);
22667  const ulongT whd = (ulongT)img._width*img._height*img._depth;
22668  cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
22669  }
22670  return _mp_arg(1);
22671  }
22672 
22673  static double mp_set_Jxyz_v(_cimg_math_parser& mp) {
22674  CImg<T> &img = mp.imgout;
22675  const double ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], oz = mp.mem[_cimg_mp_slot_z];
22676  const int
22677  x = (int)(ox + _mp_arg(2)),
22678  y = (int)(oy + _mp_arg(3)),
22679  z = (int)(oz + _mp_arg(4));
22680  const double *ptrs = &_mp_arg(1) + 1;
22681  if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
22682  const unsigned int vsiz = (unsigned int)mp.opcode[5];
22683  T *ptrd = &img(x,y,z);
22684  const ulongT whd = (ulongT)img._width*img._height*img._depth;
22685  cimg_for_inC(img,0,vsiz - 1,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
22686  }
22687  return cimg::type<double>::nan();
22688  }
22689 
22690  static double mp_shift(_cimg_math_parser& mp) {
22691  double *const ptrd = &_mp_arg(1) + 1;
22692  const double *const ptrs = &_mp_arg(2) + 1;
22693  const unsigned int siz = (unsigned int)mp.opcode[3];
22694  const int
22695  shift = (int)_mp_arg(4),
22696  boundary_conditions = (int)_mp_arg(5);
22697  CImg<doubleT>(ptrd,siz,1,1,1,true) = CImg<doubleT>(ptrs,siz,1,1,1,true).shift(shift,0,0,0,boundary_conditions);
22698  return cimg::type<double>::nan();
22699  }
22700 
22701  static double mp_sign(_cimg_math_parser& mp) {
22702  return cimg::sign(_mp_arg(2));
22703  }
22704 
22705  static double mp_sin(_cimg_math_parser& mp) {
22706  return std::sin(_mp_arg(2));
22707  }
22708 
22709  static double mp_sinc(_cimg_math_parser& mp) {
22710  return cimg::sinc(_mp_arg(2));
22711  }
22712 
22713  static double mp_sinh(_cimg_math_parser& mp) {
22714  return std::sinh(_mp_arg(2));
22715  }
22716 
22717  static double mp_solve(_cimg_math_parser& mp) {
22718  double *ptrd = &_mp_arg(1) + 1;
22719  const double
22720  *ptr1 = &_mp_arg(2) + 1,
22721  *ptr2 = &_mp_arg(3) + 1;
22722  const unsigned int
22723  k = (unsigned int)mp.opcode[4],
22724  l = (unsigned int)mp.opcode[5],
22725  m = (unsigned int)mp.opcode[6];
22726  CImg<doubleT>(ptrd,m,k,1,1,true) = CImg<doubleT>(ptr2,m,l,1,1,true).get_solve(CImg<doubleT>(ptr1,k,l,1,1,true));
22727  return cimg::type<double>::nan();
22728  }
22729 
22730  static double mp_sort(_cimg_math_parser& mp) {
22731  double *const ptrd = &_mp_arg(1) + 1;
22732  const double *const ptrs = &_mp_arg(2) + 1;
22733  const unsigned int
22734  siz = (unsigned int)mp.opcode[3],
22735  chunk_siz = (unsigned int)mp.opcode[5];
22736  const bool is_increasing = (bool)_mp_arg(4);
22737  CImg<doubleT>(ptrd,chunk_siz,siz/chunk_siz,1,1,true) = CImg<doubleT>(ptrs,chunk_siz,siz/chunk_siz,1,1,true).
22738  get_sort(is_increasing,chunk_siz>1?'y':0);
22739  return cimg::type<double>::nan();
22740  }
22741 
22742  static double mp_sqr(_cimg_math_parser& mp) {
22743  return cimg::sqr(_mp_arg(2));
22744  }
22745 
22746  static double mp_sqrt(_cimg_math_parser& mp) {
22747  return std::sqrt(_mp_arg(2));
22748  }
22749 
22750  static double mp_srand(_cimg_math_parser& mp) {
22751  return cimg::srand((unsigned int)_mp_arg(2));
22752  }
22753 
22754  static double mp_srand0(_cimg_math_parser& mp) {
22755  cimg::unused(mp);
22756  return cimg::srand();
22757  }
22758 
22759  static double mp_std(_cimg_math_parser& mp) {
22760  const unsigned int i_end = (unsigned int)mp.opcode[2];
22761  CImg<doubleT> vals(i_end - 3);
22762  double *p = vals.data();
22763  for (unsigned int i = 3; i<i_end; ++i) *(p++) = _mp_arg(i);
22764  return std::sqrt(vals.variance());
22765  }
22766 
22767  static double mp_string_init(_cimg_math_parser& mp) {
22768  const char *ptrs = (char*)&mp.opcode[3];
22769  unsigned int
22770  ptrd = (unsigned int)mp.opcode[1] + 1,
22771  siz = (unsigned int)mp.opcode[2];
22772  while (siz-->0) mp.mem[ptrd++] = (double)*(ptrs++);
22773  return cimg::type<double>::nan();
22774  }
22775 
22776  static double mp_stov(_cimg_math_parser& mp) {
22777  const double *ptrs = &_mp_arg(2);
22778  const ulongT siz = (ulongT)mp.opcode[3];
22779  longT ind = (longT)_mp_arg(4);
22780  const bool is_strict = (bool)_mp_arg(5);
22781  double val = cimg::type<double>::nan();
22782  if (ind<0 || ind>=(longT)siz) return val;
22783  if (!siz) return *ptrs>='0' && *ptrs<='9'?*ptrs - '0':val;
22784 
22785  CImg<charT> ss(siz + 1 - ind);
22786  char sep;
22787  ptrs+=1 + ind; cimg_forX(ss,i) ss[i] = (char)*(ptrs++); ss.back() = 0;
22788 
22789  int err = std::sscanf(ss,"%lf%c",&val,&sep);
22790 #if cimg_OS==2
22791  // Check for +/-NaN and +/-inf as Microsoft's sscanf() version is not able
22792  // to read those particular values.
22793  if (!err && (*ss=='+' || *ss=='-' || *ss=='i' || *ss=='I' || *ss=='n' || *ss=='N')) {
22794  bool is_positive = true;
22795  const char *s = ss;
22796  if (*s=='+') ++s; else if (*s=='-') { ++s; is_positive = false; }
22797  if (!cimg::strcasecmp(s,"inf")) { val = cimg::type<double>::inf(); err = 1; }
22798  else if (!cimg::strcasecmp(s,"nan")) { val = cimg::type<double>::nan(); err = 1; }
22799  if (err==1 && !is_positive) val = -val;
22800  }
22801 #endif
22802  if (is_strict && err!=1) return cimg::type<double>::nan();
22803  return val;
22804  }
22805 
22806  static double mp_sub(_cimg_math_parser& mp) {
22807  return _mp_arg(2) - _mp_arg(3);
22808  }
22809 
22810  static double mp_sum(_cimg_math_parser& mp) {
22811  const unsigned int i_end = (unsigned int)mp.opcode[2];
22812  double val = _mp_arg(3);
22813  for (unsigned int i = 4; i<i_end; ++i) val+=_mp_arg(i);
22814  return val;
22815  }
22816 
22817  static double mp_tan(_cimg_math_parser& mp) {
22818  return std::tan(_mp_arg(2));
22819  }
22820 
22821  static double mp_tanh(_cimg_math_parser& mp) {
22822  return std::tanh(_mp_arg(2));
22823  }
22824 
22825  static double mp_trace(_cimg_math_parser& mp) {
22826  const double *ptrs = &_mp_arg(2) + 1;
22827  const unsigned int k = (unsigned int)mp.opcode[3];
22828  return CImg<doubleT>(ptrs,k,k,1,1,true).trace();
22829  }
22830 
22831  static double mp_transp(_cimg_math_parser& mp) {
22832  double *ptrd = &_mp_arg(1) + 1;
22833  const double *ptrs = &_mp_arg(2) + 1;
22834  const unsigned int
22835  k = (unsigned int)mp.opcode[3],
22836  l = (unsigned int)mp.opcode[4];
22837  CImg<doubleT>(ptrd,l,k,1,1,true) = CImg<doubleT>(ptrs,k,l,1,1,true).get_transpose();
22838  return cimg::type<double>::nan();
22839  }
22840 
22841  static double mp_u(_cimg_math_parser& mp) {
22842  return cimg::rand(_mp_arg(2),_mp_arg(3));
22843  }
22844 
22845  static double mp_uppercase(_cimg_math_parser& mp) {
22846  return cimg::uppercase(_mp_arg(2));
22847  }
22848 
22849  static double mp_variance(_cimg_math_parser& mp) {
22850  const unsigned int i_end = (unsigned int)mp.opcode[2];
22851  CImg<doubleT> vals(i_end - 3);
22852  double *p = vals.data();
22853  for (unsigned int i = 3; i<i_end; ++i) *(p++) = _mp_arg(i);
22854  return vals.variance();
22855  }
22856 
22857  static double mp_vector_copy(_cimg_math_parser& mp) {
22858  std::memcpy(&_mp_arg(1) + 1,&_mp_arg(2) + 1,sizeof(double)*mp.opcode[3]);
22859  return cimg::type<double>::nan();
22860  }
22861 
22862  static double mp_vector_crop(_cimg_math_parser& mp) {
22863  double *const ptrd = &_mp_arg(1) + 1;
22864  const double *const ptrs = &_mp_arg(2) + 1;
22865  const longT
22866  length = (longT)mp.opcode[3],
22867  start = (longT)_mp_arg(4),
22868  sublength = (longT)mp.opcode[5];
22869  if (start<0 || start + sublength>length)
22870  throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Value accessor '[]': "
22871  "Out-of-bounds sub-vector request "
22872  "(length: %ld, start: %ld, sub-length: %ld).",
22873  mp.imgin.pixel_type(),length,start,sublength);
22874  std::memcpy(ptrd,ptrs + start,sublength*sizeof(double));
22875  return cimg::type<double>::nan();
22876  }
22877 
22878  static double mp_vector_init(_cimg_math_parser& mp) {
22879  unsigned int
22880  ptrs = 4U,
22881  ptrd = (unsigned int)mp.opcode[1] + 1,
22882  siz = (unsigned int)mp.opcode[3];
22883  switch (mp.opcode[2] - 4) {
22884  case 0 : std::memset(mp.mem._data + ptrd,0,siz*sizeof(double)); break; // 0 values given
22885  case 1 : { const double val = _mp_arg(ptrs); while (siz-->0) mp.mem[ptrd++] = val; } break;
22886  default : while (siz-->0) { mp.mem[ptrd++] = _mp_arg(ptrs++); if (ptrs>=mp.opcode[2]) ptrs = 4U; }
22887  }
22888  return cimg::type<double>::nan();
22889  }
22890 
22891  static double mp_vector_eq(_cimg_math_parser& mp) {
22892  const double
22893  *ptr1 = &_mp_arg(2) + 1,
22894  *ptr2 = &_mp_arg(4) + 1;
22895  unsigned int p1 = (unsigned int)mp.opcode[3], p2 = (unsigned int)mp.opcode[5], n;
22896  const int N = (int)_mp_arg(6);
22897  const bool case_sensitive = (bool)_mp_arg(7);
22898  bool still_equal = true;
22899  double value;
22900  if (!N) return true;
22901 
22902  // Compare all values.
22903  if (N<0) {
22904  if (p1>0 && p2>0) { // Vector == vector
22905  if (p1!=p2) return false;
22906  if (case_sensitive)
22907  while (still_equal && p1--) still_equal = *(ptr1++)==*(ptr2++);
22908  else
22909  while (still_equal && p1--)
22910  still_equal = cimg::lowercase(*(ptr1++))==cimg::lowercase(*(ptr2++));
22911  return still_equal;
22912  } else if (p1>0 && !p2) { // Vector == scalar
22913  value = _mp_arg(4);
22914  if (!case_sensitive) value = cimg::lowercase(value);
22915  while (still_equal && p1--) still_equal = *(ptr1++)==value;
22916  return still_equal;
22917  } else if (!p1 && p2>0) { // Scalar == vector
22918  value = _mp_arg(2);
22919  if (!case_sensitive) value = cimg::lowercase(value);
22920  while (still_equal && p2--) still_equal = *(ptr2++)==value;
22921  return still_equal;
22922  } else { // Scalar == scalar
22923  if (case_sensitive) return _mp_arg(2)==_mp_arg(4);
22924  else return cimg::lowercase(_mp_arg(2))==cimg::lowercase(_mp_arg(4));
22925  }
22926  }
22927 
22928  // Compare only first N values.
22929  if (p1>0 && p2>0) { // Vector == vector
22930  n = cimg::min((unsigned int)N,p1,p2);
22931  if (case_sensitive)
22932  while (still_equal && n--) still_equal = *(ptr1++)==(*ptr2++);
22933  else
22934  while (still_equal && n--) still_equal = cimg::lowercase(*(ptr1++))==cimg::lowercase(*(ptr2++));
22935  return still_equal;
22936  } else if (p1>0 && !p2) { // Vector == scalar
22937  n = std::min((unsigned int)N,p1);
22938  value = _mp_arg(4);
22939  if (!case_sensitive) value = cimg::lowercase(value);
22940  while (still_equal && n--) still_equal = *(ptr1++)==value;
22941  return still_equal;
22942  } else if (!p1 && p2>0) { // Scalar == vector
22943  n = std::min((unsigned int)N,p2);
22944  value = _mp_arg(2);
22945  if (!case_sensitive) value = cimg::lowercase(value);
22946  while (still_equal && n--) still_equal = *(ptr2++)==value;
22947  return still_equal;
22948  } // Scalar == scalar
22949  if (case_sensitive) return _mp_arg(2)==_mp_arg(4);
22950  return cimg::lowercase(_mp_arg(2))==cimg::lowercase(_mp_arg(4));
22951  }
22952 
22953  static double mp_vector_off(_cimg_math_parser& mp) {
22954  const unsigned int
22955  ptr = (unsigned int)mp.opcode[2] + 1,
22956  siz = (unsigned int)mp.opcode[3];
22957  const int off = (int)_mp_arg(4);
22958  return off>=0 && off<(int)siz?mp.mem[ptr + off]:cimg::type<double>::nan();
22959  }
22960 
22961  static double mp_vector_map_sv(_cimg_math_parser& mp) { // Operator(scalar,vector)
22962  unsigned int
22963  siz = (unsigned int)mp.opcode[2],
22964  ptrs = (unsigned int)mp.opcode[5] + 1;
22965  double *ptrd = &_mp_arg(1) + 1;
22966  mp_func op = (mp_func)mp.opcode[3];
22967  CImg<ulongT> l_opcode(4);
22968  l_opcode[2] = mp.opcode[4]; // Scalar argument1
22969  l_opcode.swap(mp.opcode);
22970  ulongT &argument2 = mp.opcode[3];
22971  while (siz-->0) { argument2 = ptrs++; *(ptrd++) = (*op)(mp); }
22972  l_opcode.swap(mp.opcode);
22973  return cimg::type<double>::nan();
22974  }
22975 
22976  static double mp_vector_map_v(_cimg_math_parser& mp) { // Operator(vector)
22977  unsigned int
22978  siz = (unsigned int)mp.opcode[2],
22979  ptrs = (unsigned int)mp.opcode[4] + 1;
22980  double *ptrd = &_mp_arg(1) + 1;
22981  mp_func op = (mp_func)mp.opcode[3];
22982  CImg<ulongT> l_opcode(1,3);
22983  l_opcode.swap(mp.opcode);
22984  ulongT &argument = mp.opcode[2];
22985  while (siz-->0) { argument = ptrs++; *(ptrd++) = (*op)(mp); }
22986  l_opcode.swap(mp.opcode);
22987  return cimg::type<double>::nan();
22988  }
22989 
22990  static double mp_vector_map_vs(_cimg_math_parser& mp) { // Operator(vector,scalar)
22991  unsigned int
22992  siz = (unsigned int)mp.opcode[2],
22993  ptrs = (unsigned int)mp.opcode[4] + 1;
22994  double *ptrd = &_mp_arg(1) + 1;
22995  mp_func op = (mp_func)mp.opcode[3];
22996  CImg<ulongT> l_opcode(1,4);
22997  l_opcode[3] = mp.opcode[5]; // Scalar argument2
22998  l_opcode.swap(mp.opcode);
22999  ulongT &argument1 = mp.opcode[2];
23000  while (siz-->0) { argument1 = ptrs++; *(ptrd++) = (*op)(mp); }
23001  l_opcode.swap(mp.opcode);
23002  return cimg::type<double>::nan();
23003  }
23004 
23005  static double mp_vector_map_vss(_cimg_math_parser& mp) { // Operator(vector,scalar,scalar)
23006  unsigned int
23007  siz = (unsigned int)mp.opcode[2],
23008  ptrs = (unsigned int)mp.opcode[4] + 1;
23009  double *ptrd = &_mp_arg(1) + 1;
23010  mp_func op = (mp_func)mp.opcode[3];
23011  CImg<ulongT> l_opcode(1,5);
23012  l_opcode[3] = mp.opcode[5]; // Scalar argument2
23013  l_opcode[4] = mp.opcode[6]; // Scalar argument3
23014  l_opcode.swap(mp.opcode);
23015  ulongT &argument1 = mp.opcode[2];
23016  while (siz-->0) { argument1 = ptrs++; *(ptrd++) = (*op)(mp); }
23017  l_opcode.swap(mp.opcode);
23018  return cimg::type<double>::nan();
23019  }
23020 
23021  static double mp_vector_map_vv(_cimg_math_parser& mp) { // Operator(vector,vector)
23022  unsigned int
23023  siz = (unsigned int)mp.opcode[2],
23024  ptrs1 = (unsigned int)mp.opcode[4] + 1,
23025  ptrs2 = (unsigned int)mp.opcode[5] + 1;
23026  double *ptrd = &_mp_arg(1) + 1;
23027  mp_func op = (mp_func)mp.opcode[3];
23028  CImg<ulongT> l_opcode(1,4);
23029  l_opcode.swap(mp.opcode);
23030  ulongT &argument1 = mp.opcode[2], &argument2 = mp.opcode[3];
23031  while (siz-->0) { argument1 = ptrs1++; argument2 = ptrs2++; *(ptrd++) = (*op)(mp); }
23032  l_opcode.swap(mp.opcode);
23033  return cimg::type<double>::nan();
23034  }
23035 
23036  static double mp_vector_neq(_cimg_math_parser& mp) {
23037  return !mp_vector_eq(mp);
23038  }
23039 
23040  static double mp_vector_print(_cimg_math_parser& mp) {
23041  const bool print_string = (bool)mp.opcode[4];
23042  cimg_pragma_openmp(critical(mp_vector_print))
23043  {
23044  CImg<charT> expr(mp.opcode[2] - 5);
23045  const ulongT *ptrs = mp.opcode._data + 5;
23046  cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++);
23047  cimg::strellipsize(expr);
23048  unsigned int
23049  ptr = (unsigned int)mp.opcode[1] + 1,
23050  siz0 = (unsigned int)mp.opcode[3],
23051  siz = siz0;
23052  cimg::mutex(6);
23053  std::fprintf(cimg::output(),"\n[" cimg_appname "_math_parser] %s = [ ",expr._data);
23054  unsigned int count = 0;
23055  while (siz-->0) {
23056  if (count>=64 && siz>=64) {
23057  std::fprintf(cimg::output(),"...,");
23058  ptr = (unsigned int)mp.opcode[1] + 1 + siz0 - 64;
23059  siz = 64;
23060  } else std::fprintf(cimg::output(),"%g%s",mp.mem[ptr++],siz?",":"");
23061  ++count;
23062  }
23063  if (print_string) {
23064  CImg<charT> str(siz0 + 1);
23065  ptr = (unsigned int)mp.opcode[1] + 1;
23066  for (unsigned int k = 0; k<siz0; ++k) str[k] = (char)mp.mem[ptr++];
23067  str[siz0] = 0;
23068  cimg::strellipsize(str,1024,false);
23069  std::fprintf(cimg::output()," ] = '%s' (size: %u)",str._data,siz0);
23070  } else std::fprintf(cimg::output()," ] (size: %u)",siz0);
23071  std::fflush(cimg::output());
23072  cimg::mutex(6,0);
23073  }
23074  return cimg::type<double>::nan();
23075  }
23076 
23077  static double mp_vector_resize(_cimg_math_parser& mp) {
23078  double *const ptrd = &_mp_arg(1) + 1;
23079  const unsigned int p1 = (unsigned int)mp.opcode[2], p2 = (unsigned int)mp.opcode[4];
23080  const int
23081  interpolation = (int)_mp_arg(5),
23082  boundary_conditions = (int)_mp_arg(6);
23083  if (p2) { // Resize vector
23084  const double *const ptrs = &_mp_arg(3) + 1;
23085  CImg<doubleT>(ptrd,p1,1,1,1,true) = CImg<doubleT>(ptrs,p2,1,1,1,true).
23086  get_resize(p1,1,1,1,interpolation,boundary_conditions);
23087  } else { // Resize scalar
23088  const double value = _mp_arg(3);
23089  CImg<doubleT>(ptrd,p1,1,1,1,true) = CImg<doubleT>(1,1,1,1,value).resize(p1,1,1,1,interpolation,
23090  boundary_conditions);
23091  }
23092  return cimg::type<double>::nan();
23093  }
23094 
23095  static double mp_vector_reverse(_cimg_math_parser& mp) {
23096  double *const ptrd = &_mp_arg(1) + 1;
23097  const double *const ptrs = &_mp_arg(2) + 1;
23098  const unsigned int p1 = (unsigned int)mp.opcode[3];
23099  CImg<doubleT>(ptrd,p1,1,1,1,true) = CImg<doubleT>(ptrs,p1,1,1,1,true).get_mirror('x');
23100  return cimg::type<double>::nan();
23101  }
23102 
23103  static double mp_vector_set_off(_cimg_math_parser& mp) {
23104  const unsigned int
23105  ptr = (unsigned int)mp.opcode[2] + 1,
23106  siz = (unsigned int)mp.opcode[3];
23107  const int off = (int)_mp_arg(4);
23108  if (off>=0 && off<(int)siz) mp.mem[ptr + off] = _mp_arg(5);
23109  return _mp_arg(5);
23110  }
23111 
23112  static double mp_vtos(_cimg_math_parser& mp) {
23113  double *ptrd = &_mp_arg(1) + 1;
23114  const unsigned int
23115  sizd = (unsigned int)mp.opcode[2],
23116  sizs = (unsigned int)mp.opcode[4];
23117  const int nb_digits = (int)_mp_arg(5);
23118  CImg<charT> format(8);
23119  switch (nb_digits) {
23120  case -1 : std::strcpy(format,"%g"); break;
23121  case 0 : std::strcpy(format,"%.17g"); break;
23122  default : cimg_snprintf(format,format._width,"%%.%dg",nb_digits);
23123  }
23124  CImg<charT> str;
23125  if (sizs) { // Vector expression
23126  const double *ptrs = &_mp_arg(3) + 1;
23127  CImg<doubleT>(ptrs,sizs,1,1,1,true).value_string(',',sizd + 1,format).move_to(str);
23128  } else { // Scalar expression
23129  str.assign(sizd + 1);
23130  cimg_snprintf(str,sizd + 1,format,_mp_arg(3));
23131  }
23132  const unsigned int l = std::min(sizd,(unsigned int)std::strlen(str) + 1);
23133  CImg<doubleT>(ptrd,l,1,1,1,true) = str.get_shared_points(0,l - 1);
23134  return cimg::type<double>::nan();
23135  }
23136 
23137  static double mp_whiledo(_cimg_math_parser& mp) {
23138  const ulongT
23139  mem_body = mp.opcode[1],
23140  mem_cond = mp.opcode[2];
23141  const CImg<ulongT>
23142  *const p_cond = ++mp.p_code,
23143  *const p_body = p_cond + mp.opcode[3],
23144  *const p_end = p_body + mp.opcode[4];
23145  const unsigned int vsiz = (unsigned int)mp.opcode[5];
23146  bool is_cond = false;
23147  if (mp.opcode[6]) { // Set default value for result and condition if necessary
23148  if (vsiz) CImg<doubleT>(&mp.mem[mem_body] + 1,vsiz,1,1,1,true).fill(cimg::type<double>::nan());
23149  else mp.mem[mem_body] = cimg::type<double>::nan();
23150  }
23151  if (mp.opcode[7]) mp.mem[mem_cond] = 0;
23152  const unsigned int _break_type = mp.break_type;
23153  mp.break_type = 0;
23154  do {
23155  for (mp.p_code = p_cond; mp.p_code<p_body; ++mp.p_code) { // Evaluate condition
23156  mp.opcode._data = mp.p_code->_data;
23157  const ulongT target = mp.opcode[1];
23158  mp.mem[target] = _cimg_mp_defunc(mp);
23159  }
23160  if (mp.break_type==1) break;
23161  is_cond = (bool)mp.mem[mem_cond];
23162  if (is_cond && !mp.break_type) // Evaluate body
23163  for (mp.p_code = p_body; mp.p_code<p_end; ++mp.p_code) {
23164  mp.opcode._data = mp.p_code->_data;
23165  const ulongT target = mp.opcode[1];
23166  mp.mem[target] = _cimg_mp_defunc(mp);
23167  }
23168  if (mp.break_type==1) break; else if (mp.break_type==2) mp.break_type = 0;
23169  } while (is_cond);
23170 
23171  mp.break_type = _break_type;
23172  mp.p_code = p_end - 1;
23173  return mp.mem[mem_body];
23174  }
23175 
23176  static double mp_Ioff(_cimg_math_parser& mp) {
23177  double *ptrd = &_mp_arg(1) + 1;
23178  const unsigned int
23179  boundary_conditions = (unsigned int)_mp_arg(3),
23180  vsiz = (unsigned int)mp.opcode[4];
23181  const CImg<T> &img = mp.imgin;
23182  const longT
23183  off = (longT)_mp_arg(2),
23184  whd = (longT)img.width()*img.height()*img.depth();
23185  const T *ptrs;
23186  if (off>=0 && off<whd) {
23187  ptrs = &img[off];
23188  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
23189  return cimg::type<double>::nan();
23190  }
23191  if (img._data) switch (boundary_conditions) {
23192  case 3 : { // Mirror
23193  const longT whd2 = 2*whd, moff = cimg::mod(off,whd2);
23194  ptrs = &img[moff<whd?moff:whd2 - moff - 1];
23195  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
23196  return cimg::type<double>::nan();
23197  }
23198  case 2 : // Periodic
23199  ptrs = &img[cimg::mod(off,whd)];
23200  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
23201  return cimg::type<double>::nan();
23202  case 1 : // Neumann
23203  ptrs = off<0?&img[0]:&img[whd - 1];
23204  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
23205  return cimg::type<double>::nan();
23206  default : // Dirichlet
23207  std::memset(ptrd,0,vsiz*sizeof(double));
23208  return cimg::type<double>::nan();
23209  }
23210  std::memset(ptrd,0,vsiz*sizeof(double));
23211  return cimg::type<double>::nan();
23212  }
23213 
23214  static double mp_Ixyz(_cimg_math_parser& mp) {
23215  double *ptrd = &_mp_arg(1) + 1;
23216  const unsigned int
23217  interpolation = (unsigned int)_mp_arg(5),
23218  boundary_conditions = (unsigned int)_mp_arg(6),
23219  vsiz = (unsigned int)mp.opcode[7];
23220  const CImg<T> &img = mp.imgin;
23221  const double x = _mp_arg(2), y = _mp_arg(3), z = _mp_arg(4);
23222  const ulongT whd = (ulongT)img._width*img._height*img._depth;
23223  const T *ptrs;
23224  if (interpolation==0) switch (boundary_conditions) { // Nearest neighbor interpolation
23225  case 3 : { // Mirror
23226  const int
23227  w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(),
23228  mx = cimg::mod((int)x,w2), my = cimg::mod((int)y,h2), mz = cimg::mod((int)z,d2),
23229  cx = mx<img.width()?mx:w2 - mx - 1,
23230  cy = my<img.height()?my:h2 - my - 1,
23231  cz = mz<img.depth()?mz:d2 - mz - 1;
23232  ptrs = &img(cx,cy,cz);
23233  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
23234  } break;
23235  case 2 : { // Periodic
23236  const int
23237  cx = cimg::mod((int)x,img.width()),
23238  cy = cimg::mod((int)y,img.height()),
23239  cz = cimg::mod((int)z,img.depth());
23240  ptrs = &img(cx,cy,cz);
23241  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
23242  } break;
23243  case 1 : { // Neumann
23244  ptrs = &img._atXYZ((int)x,(int)y,(int)z);
23245  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
23246  } break;
23247  default : // Dirichlet
23248  if (img.containsXYZC(x,y,z)) {
23249  ptrs = &img((int)x,(int)y,(int)z);
23250  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
23251  } else std::memset(ptrd,0,vsiz*sizeof(double));
23252  } else switch (boundary_conditions) { // Linear interpolation
23253  case 3 : { // Mirror
23254  const float
23255  w2 = 2.0f*img.width(), h2 = 2.0f*img.height(), d2 = 2.0f*img.depth(),
23256  mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), mz = cimg::mod((float)z,d2),
23257  cx = mx<img.width()?mx:w2 - mx - 1,
23258  cy = my<img.height()?my:h2 - my - 1,
23259  cz = mz<img.depth()?mz:d2 - mz - 1;
23260  cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ(cx,cy,cz,c);
23261  } break;
23262  case 2 : { // Periodic
23263  const float
23264  cx = cimg::mod((float)x,(float)img.width()),
23265  cy = cimg::mod((float)y,(float)img.height()),
23266  cz = cimg::mod((float)z,(float)img.depth());
23267  cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ(cx,cy,cz,c);
23268  } break;
23269  case 1 : // Neumann
23270  cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ((float)x,(float)y,(float)z,c);
23271  break;
23272  default : // Dirichlet
23273  cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,(T)0);
23274  }
23275  return cimg::type<double>::nan();
23276  }
23277 
23278  static double mp_Joff(_cimg_math_parser& mp) {
23279  double *ptrd = &_mp_arg(1) + 1;
23280  const unsigned int
23281  boundary_conditions = (unsigned int)_mp_arg(3),
23282  vsiz = (unsigned int)mp.opcode[4];
23283  const CImg<T> &img = mp.imgin;
23284  const int
23285  ox = (int)mp.mem[_cimg_mp_slot_x],
23286  oy = (int)mp.mem[_cimg_mp_slot_y],
23287  oz = (int)mp.mem[_cimg_mp_slot_z];
23288  const longT
23289  off = img.offset(ox,oy,oz) + (longT)_mp_arg(2),
23290  whd = (longT)img.width()*img.height()*img.depth();
23291  const T *ptrs;
23292  if (off>=0 && off<whd) {
23293  ptrs = &img[off];
23294  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
23295  return cimg::type<double>::nan();
23296  }
23297  if (img._data) switch (boundary_conditions) {
23298  case 3 : { // Mirror
23299  const longT whd2 = 2*whd, moff = cimg::mod(off,whd2);
23300  ptrs = &img[moff<whd?moff:whd2 - moff - 1];
23301  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
23302  return cimg::type<double>::nan();
23303  }
23304  case 2 : // Periodic
23305  ptrs = &img[cimg::mod(off,whd)];
23306  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
23307  return cimg::type<double>::nan();
23308  case 1 : // Neumann
23309  ptrs = off<0?&img[0]:&img[whd - 1];
23310  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
23311  return cimg::type<double>::nan();
23312  default : // Dirichlet
23313  std::memset(ptrd,0,vsiz*sizeof(double));
23314  return cimg::type<double>::nan();
23315  }
23316  std::memset(ptrd,0,vsiz*sizeof(double));
23317  return cimg::type<double>::nan();
23318  }
23319 
23320  static double mp_Jxyz(_cimg_math_parser& mp) {
23321  double *ptrd = &_mp_arg(1) + 1;
23322  const unsigned int
23323  interpolation = (unsigned int)_mp_arg(5),
23324  boundary_conditions = (unsigned int)_mp_arg(6),
23325  vsiz = (unsigned int)mp.opcode[7];
23326  const CImg<T> &img = mp.imgin;
23327  const double
23328  ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], oz = mp.mem[_cimg_mp_slot_z],
23329  x = ox + _mp_arg(2), y = oy + _mp_arg(3), z = oz + _mp_arg(4);
23330  const ulongT whd = (ulongT)img._width*img._height*img._depth;
23331  const T *ptrs;
23332  if (interpolation==0) switch (boundary_conditions) { // Nearest neighbor interpolation
23333  case 3 : { // Mirror
23334  const int
23335  w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(),
23336  mx = cimg::mod((int)x,w2), my = cimg::mod((int)y,h2), mz = cimg::mod((int)z,d2),
23337  cx = mx<img.width()?mx:w2 - mx - 1,
23338  cy = my<img.height()?my:h2 - my - 1,
23339  cz = mz<img.depth()?mz:d2 - mz - 1;
23340  ptrs = &img(cx,cy,cz);
23341  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
23342  } break;
23343  case 2 : { // Periodic
23344  const int
23345  cx = cimg::mod((int)x,img.width()),
23346  cy = cimg::mod((int)y,img.height()),
23347  cz = cimg::mod((int)z,img.depth());
23348  ptrs = &img(cx,cy,cz);
23349  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
23350  } break;
23351  case 1 : { // Neumann
23352  ptrs = &img._atXYZ((int)x,(int)y,(int)z);
23353  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
23354  } break;
23355  default : // Dirichlet
23356  if (img.containsXYZC(x,y,z)) {
23357  ptrs = &img((int)x,(int)y,(int)z);
23358  cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = (double)*ptrs; ptrs+=whd; }
23359  } else std::memset(ptrd,0,vsiz*sizeof(double));
23360  } else switch (boundary_conditions) { // Linear interpolation
23361  case 3 : { // Mirror
23362  const float
23363  w2 = 2.0f*img.width(), h2 = 2.0f*img.height(), d2 = 2.0f*img.depth(),
23364  mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), mz = cimg::mod((float)z,d2),
23365  cx = mx<img.width()?mx:w2 - mx - 1,
23366  cy = my<img.height()?my:h2 - my - 1,
23367  cz = mz<img.depth()?mz:d2 - mz - 1;
23368  cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ(cx,cy,cz,c);
23369  } break;
23370  case 2 : { // Periodic
23371  const float
23372  cx = cimg::mod((float)x,(float)img.width()),
23373  cy = cimg::mod((float)y,(float)img.height()),
23374  cz = cimg::mod((float)z,(float)img.depth());
23375  cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ(cx,cy,cz,c);
23376  } break;
23377  case 1 : // Neumann
23378  cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img._linear_atXYZ((float)x,(float)y,(float)z,c);
23379  break;
23380  default : // Dirichlet
23381  cimg_for_inC(img,0,vsiz - 1,c) *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,(T)0);
23382  }
23383  return cimg::type<double>::nan();
23384  }
23385 
23386 #undef _mp_arg
23387 
23388  }; // struct _cimg_math_parser {}
23389 
23391 
23404  if (is_empty()) return *this;
23405  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=524288))
23406  cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(val*val); };
23407  return *this;
23408  }
23409 
23412  return CImg<Tfloat>(*this,false).sqr();
23413  }
23414 
23416 
23429  if (is_empty()) return *this;
23430  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=8192))
23431  cimg_rof(*this,ptrd,T) *ptrd = (T)std::sqrt((double)*ptrd);
23432  return *this;
23433  }
23434 
23437  return CImg<Tfloat>(*this,false).sqrt();
23438  }
23439 
23441 
23448  if (is_empty()) return *this;
23449  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=4096))
23450  cimg_rof(*this,ptrd,T) *ptrd = (T)std::exp((double)*ptrd);
23451  return *this;
23452  }
23453 
23456  return CImg<Tfloat>(*this,false).exp();
23457  }
23458 
23460 
23468  if (is_empty()) return *this;
23469  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=262144))
23470  cimg_rof(*this,ptrd,T) *ptrd = (T)std::log((double)*ptrd);
23471  return *this;
23472  }
23473 
23476  return CImg<Tfloat>(*this,false).log();
23477  }
23478 
23480 
23488  if (is_empty()) return *this;
23489  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=4096))
23490  cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::log2((double)*ptrd);
23491  return *this;
23492  }
23493 
23496  return CImg<Tfloat>(*this,false).log2();
23497  }
23498 
23500 
23508  if (is_empty()) return *this;
23509  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=4096))
23510  cimg_rof(*this,ptrd,T) *ptrd = (T)std::log10((double)*ptrd);
23511  return *this;
23512  }
23513 
23516  return CImg<Tfloat>(*this,false).log10();
23517  }
23518 
23520 
23527  if (is_empty()) return *this;
23528  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=524288))
23529  cimg_rof(*this,ptrd,T) *ptrd = cimg::abs(*ptrd);
23530  return *this;
23531  }
23532 
23535  return CImg<Tfloat>(*this,false).abs();
23536  }
23537 
23539 
23551  if (is_empty()) return *this;
23552  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
23553  cimg_rof(*this,ptrd,T) *ptrd = cimg::sign(*ptrd);
23554  return *this;
23555  }
23556 
23559  return CImg<Tfloat>(*this,false).sign();
23560  }
23561 
23563 
23571  if (is_empty()) return *this;
23572  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=8192))
23573  cimg_rof(*this,ptrd,T) *ptrd = (T)std::cos((double)*ptrd);
23574  return *this;
23575  }
23576 
23579  return CImg<Tfloat>(*this,false).cos();
23580  }
23581 
23583 
23591  if (is_empty()) return *this;
23592  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=8192))
23593  cimg_rof(*this,ptrd,T) *ptrd = (T)std::sin((double)*ptrd);
23594  return *this;
23595  }
23596 
23599  return CImg<Tfloat>(*this,false).sin();
23600  }
23601 
23603 
23612  if (is_empty()) return *this;
23613  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=2048))
23614  cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::sinc((double)*ptrd);
23615  return *this;
23616  }
23617 
23620  return CImg<Tfloat>(*this,false).sinc();
23621  }
23622 
23624 
23632  if (is_empty()) return *this;
23633  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=2048))
23634  cimg_rof(*this,ptrd,T) *ptrd = (T)std::tan((double)*ptrd);
23635  return *this;
23636  }
23637 
23640  return CImg<Tfloat>(*this,false).tan();
23641  }
23642 
23644 
23652  if (is_empty()) return *this;
23653  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=2048))
23654  cimg_rof(*this,ptrd,T) *ptrd = (T)std::cosh((double)*ptrd);
23655  return *this;
23656  }
23657 
23660  return CImg<Tfloat>(*this,false).cosh();
23661  }
23662 
23664 
23672  if (is_empty()) return *this;
23673  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=2048))
23674  cimg_rof(*this,ptrd,T) *ptrd = (T)std::sinh((double)*ptrd);
23675  return *this;
23676  }
23677 
23680  return CImg<Tfloat>(*this,false).sinh();
23681  }
23682 
23684 
23692  if (is_empty()) return *this;
23693  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=2048))
23694  cimg_rof(*this,ptrd,T) *ptrd = (T)std::tanh((double)*ptrd);
23695  return *this;
23696  }
23697 
23700  return CImg<Tfloat>(*this,false).tanh();
23701  }
23702 
23704 
23712  if (is_empty()) return *this;
23713  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=8192))
23714  cimg_rof(*this,ptrd,T) *ptrd = (T)std::acos((double)*ptrd);
23715  return *this;
23716  }
23717 
23720  return CImg<Tfloat>(*this,false).acos();
23721  }
23722 
23724 
23732  if (is_empty()) return *this;
23733  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=8192))
23734  cimg_rof(*this,ptrd,T) *ptrd = (T)std::asin((double)*ptrd);
23735  return *this;
23736  }
23737 
23740  return CImg<Tfloat>(*this,false).asin();
23741  }
23742 
23744 
23752  if (is_empty()) return *this;
23753  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=8192))
23754  cimg_rof(*this,ptrd,T) *ptrd = (T)std::atan((double)*ptrd);
23755  return *this;
23756  }
23757 
23760  return CImg<Tfloat>(*this,false).atan();
23761  }
23762 
23764 
23780  template<typename t>
23781  CImg<T>& atan2(const CImg<t>& img) {
23782  const ulongT siz = size(), isiz = img.size();
23783  if (siz && isiz) {
23784  if (is_overlapped(img)) return atan2(+img);
23785  T *ptrd = _data, *const ptre = _data + siz;
23786  if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
23787  for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
23788  *ptrd = (T)std::atan2((double)*ptrd,(double)*(ptrs++));
23789  for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)std::atan2((double)*ptrd,(double)*(ptrs++));
23790  }
23791  return *this;
23792  }
23793 
23795  template<typename t>
23796  CImg<Tfloat> get_atan2(const CImg<t>& img) const {
23797  return CImg<Tfloat>(*this,false).atan2(img);
23798  }
23799 
23801 
23817  template<typename t>
23818  CImg<T>& mul(const CImg<t>& img) {
23819  const ulongT siz = size(), isiz = img.size();
23820  if (siz && isiz) {
23821  if (is_overlapped(img)) return mul(+img);
23822  T *ptrd = _data, *const ptre = _data + siz;
23823  if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
23824  for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
23825  *ptrd = (T)(*ptrd * *(ptrs++));
23826  for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)(*ptrd * *(ptrs++));
23827  }
23828  return *this;
23829  }
23830 
23832  template<typename t>
23833  CImg<_cimg_Tt> get_mul(const CImg<t>& img) const {
23834  return CImg<_cimg_Tt>(*this,false).mul(img);
23835  }
23836 
23838 
23841  template<typename t>
23842  CImg<T>& div(const CImg<t>& img) {
23843  const ulongT siz = size(), isiz = img.size();
23844  if (siz && isiz) {
23845  if (is_overlapped(img)) return div(+img);
23846  T *ptrd = _data, *const ptre = _data + siz;
23847  if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
23848  for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
23849  *ptrd = (T)(*ptrd / *(ptrs++));
23850  for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)(*ptrd / *(ptrs++));
23851  }
23852  return *this;
23853  }
23854 
23856  template<typename t>
23857  CImg<_cimg_Tt> get_div(const CImg<t>& img) const {
23858  return CImg<_cimg_Tt>(*this,false).div(img);
23859  }
23860 
23862 
23877  CImg<T>& pow(const double p) {
23878  if (is_empty()) return *this;
23879  if (p==-4) {
23880  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
23881  cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val*val*val)); }
23882  return *this;
23883  }
23884  if (p==-3) {
23885  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
23886  cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val*val)); }
23887  return *this;
23888  }
23889  if (p==-2) {
23890  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
23891  cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val)); }
23892  return *this;
23893  }
23894  if (p==-1) {
23895  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
23896  cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/val); }
23897  return *this;
23898  }
23899  if (p==-0.5) {
23900  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=8192))
23901  cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1/std::sqrt((double)val)); }
23902  return *this;
23903  }
23904  if (p==0) return fill((T)1);
23905  if (p==0.25) return sqrt().sqrt();
23906  if (p==0.5) return sqrt();
23907  if (p==1) return *this;
23908  if (p==2) return sqr();
23909  if (p==3) {
23910  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=262144))
23911  cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val; }
23912  return *this;
23913  }
23914  if (p==4) {
23915  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=131072))
23916  cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val*val; }
23917  return *this;
23918  }
23919  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=1024))
23920  cimg_rof(*this,ptrd,T) *ptrd = (T)std::pow((double)*ptrd,p);
23921  return *this;
23922  }
23923 
23925  CImg<Tfloat> get_pow(const double p) const {
23926  return CImg<Tfloat>(*this,false).pow(p);
23927  }
23928 
23930 
23933  CImg<T>& pow(const char *const expression) {
23934  return pow((+*this)._fill(expression,true,true,0,0,"pow",this));
23935  }
23936 
23938  CImg<Tfloat> get_pow(const char *const expression) const {
23939  return CImg<Tfloat>(*this,false).pow(expression);
23940  }
23941 
23943 
23946  template<typename t>
23947  CImg<T>& pow(const CImg<t>& img) {
23948  const ulongT siz = size(), isiz = img.size();
23949  if (siz && isiz) {
23950  if (is_overlapped(img)) return pow(+img);
23951  T *ptrd = _data, *const ptre = _data + siz;
23952  if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
23953  for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
23954  *ptrd = (T)std::pow((double)*ptrd,(double)(*(ptrs++)));
23955  for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)std::pow((double)*ptrd,(double)(*(ptrs++)));
23956  }
23957  return *this;
23958  }
23959 
23961  template<typename t>
23962  CImg<Tfloat> get_pow(const CImg<t>& img) const {
23963  return CImg<Tfloat>(*this,false).pow(img);
23964  }
23965 
23967 
23970  CImg<T>& rol(const unsigned int n=1) {
23971  if (is_empty()) return *this;
23972  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
23973  cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::rol(*ptrd,n);
23974  return *this;
23975  }
23976 
23978  CImg<T> get_rol(const unsigned int n=1) const {
23979  return (+*this).rol(n);
23980  }
23981 
23983 
23986  CImg<T>& rol(const char *const expression) {
23987  return rol((+*this)._fill(expression,true,true,0,0,"rol",this));
23988  }
23989 
23991  CImg<T> get_rol(const char *const expression) const {
23992  return (+*this).rol(expression);
23993  }
23994 
23996 
23999  template<typename t>
24000  CImg<T>& rol(const CImg<t>& img) {
24001  const ulongT siz = size(), isiz = img.size();
24002  if (siz && isiz) {
24003  if (is_overlapped(img)) return rol(+img);
24004  T *ptrd = _data, *const ptre = _data + siz;
24005  if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
24006  for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
24007  *ptrd = (T)cimg::rol(*ptrd,(unsigned int)(*(ptrs++)));
24008  for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)cimg::rol(*ptrd,(unsigned int)(*(ptrs++)));
24009  }
24010  return *this;
24011  }
24012 
24014  template<typename t>
24015  CImg<T> get_rol(const CImg<t>& img) const {
24016  return (+*this).rol(img);
24017  }
24018 
24020 
24023  CImg<T>& ror(const unsigned int n=1) {
24024  if (is_empty()) return *this;
24025  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
24026  cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::ror(*ptrd,n);
24027  return *this;
24028  }
24029 
24031  CImg<T> get_ror(const unsigned int n=1) const {
24032  return (+*this).ror(n);
24033  }
24034 
24036 
24039  CImg<T>& ror(const char *const expression) {
24040  return ror((+*this)._fill(expression,true,true,0,0,"ror",this));
24041  }
24042 
24044  CImg<T> get_ror(const char *const expression) const {
24045  return (+*this).ror(expression);
24046  }
24047 
24049 
24052  template<typename t>
24053  CImg<T>& ror(const CImg<t>& img) {
24054  const ulongT siz = size(), isiz = img.size();
24055  if (siz && isiz) {
24056  if (is_overlapped(img)) return ror(+img);
24057  T *ptrd = _data, *const ptre = _data + siz;
24058  if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
24059  for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
24060  *ptrd = (T)cimg::ror(*ptrd,(unsigned int)(*(ptrs++)));
24061  for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)cimg::ror(*ptrd,(unsigned int)(*(ptrs++)));
24062  }
24063  return *this;
24064  }
24065 
24067  template<typename t>
24068  CImg<T> get_ror(const CImg<t>& img) const {
24069  return (+*this).ror(img);
24070  }
24071 
24073 
24078  CImg<T>& min(const T& val) {
24079  if (is_empty()) return *this;
24080  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=65536))
24081  cimg_rof(*this,ptrd,T) *ptrd = std::min(*ptrd,val);
24082  return *this;
24083  }
24084 
24086  CImg<T> get_min(const T& val) const {
24087  return (+*this).min(val);
24088  }
24089 
24091 
24096  template<typename t>
24097  CImg<T>& min(const CImg<t>& img) {
24098  const ulongT siz = size(), isiz = img.size();
24099  if (siz && isiz) {
24100  if (is_overlapped(img)) return min(+img);
24101  T *ptrd = _data, *const ptre = _data + siz;
24102  if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
24103  for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
24104  *ptrd = std::min((T)*(ptrs++),*ptrd);
24105  for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = std::min((T)*(ptrs++),*ptrd);
24106  }
24107  return *this;
24108  }
24109 
24111  template<typename t>
24112  CImg<_cimg_Tt> get_min(const CImg<t>& img) const {
24113  return CImg<_cimg_Tt>(*this,false).min(img);
24114  }
24115 
24117 
24122  CImg<T>& min(const char *const expression) {
24123  return min((+*this)._fill(expression,true,true,0,0,"min",this));
24124  }
24125 
24127  CImg<Tfloat> get_min(const char *const expression) const {
24128  return CImg<Tfloat>(*this,false).min(expression);
24129  }
24130 
24132 
24137  CImg<T>& max(const T& val) {
24138  if (is_empty()) return *this;
24139  cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=65536))
24140  cimg_rof(*this,ptrd,T) *ptrd = std::max(*ptrd,val);
24141  return *this;
24142  }
24143 
24145  CImg<T> get_max(const T& val) const {
24146  return (+*this).max(val);
24147  }
24148 
24150 
24155  template<typename t>
24156  CImg<T>& max(const CImg<t>& img) {
24157  const ulongT siz = size(), isiz = img.size();
24158  if (siz && isiz) {
24159  if (is_overlapped(img)) return max(+img);
24160  T *ptrd = _data, *const ptre = _data + siz;
24161  if (siz>isiz) for (ulongT n = siz/isiz; n; --n)
24162  for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd)
24163  *ptrd = std::max((T)*(ptrs++),*ptrd);
24164  for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = std::max((T)*(ptrs++),*ptrd);
24165  }
24166  return *this;
24167  }
24168 
24170  template<typename t>
24171  CImg<_cimg_Tt> get_max(const CImg<t>& img) const {
24172  return CImg<_cimg_Tt>(*this,false).max(img);
24173  }
24174 
24176 
24181  CImg<T>& max(const char *const expression) {
24182  return max((+*this)._fill(expression,true,true,0,0,"max",this));
24183  }
24184 
24186  CImg<Tfloat> get_max(const char *const expression) const {
24187  return CImg<Tfloat>(*this,false).max(expression);
24188  }
24189 
24191 
24193  T& min() {
24194  if (is_empty())
24195  throw CImgInstanceException(_cimg_instance
24196  "min(): Empty instance.",
24197  cimg_instance);
24198  T *ptr_min = _data;
24199  T min_value = *ptr_min;
24200  cimg_for(*this,ptrs,T) if (*ptrs<min_value) min_value = *(ptr_min=ptrs);
24201  return *ptr_min;
24202  }
24203 
24205  const T& min() const {
24206  if (is_empty())
24207  throw CImgInstanceException(_cimg_instance
24208  "min(): Empty instance.",
24209  cimg_instance);
24210  const T *ptr_min = _data;
24211  T min_value = *ptr_min;
24212  cimg_for(*this,ptrs,T) if (*ptrs<min_value) min_value = *(ptr_min=ptrs);
24213  return *ptr_min;
24214  }
24215 
24217 
24219  T& max() {
24220  if (is_empty())
24221  throw CImgInstanceException(_cimg_instance
24222  "max(): Empty instance.",
24223  cimg_instance);
24224  T *ptr_max = _data;
24225  T max_value = *ptr_max;
24226  cimg_for(*this,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs);
24227  return *ptr_max;
24228  }
24229 
24231  const T& max() const {
24232  if (is_empty())
24233  throw CImgInstanceException(_cimg_instance
24234  "max(): Empty instance.",
24235  cimg_instance);
24236  const T *ptr_max = _data;
24237  T max_value = *ptr_max;
24238  cimg_for(*this,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs);
24239  return *ptr_max;
24240  }
24241 
24243 
24246  template<typename t>
24247  T& min_max(t& max_val) {
24248  if (is_empty())
24249  throw CImgInstanceException(_cimg_instance
24250  "min_max(): Empty instance.",
24251  cimg_instance);
24252  T *ptr_min = _data;
24253  T min_value = *ptr_min, max_value = min_value;
24254  cimg_for(*this,ptrs,T) {
24255  const T val = *ptrs;
24256  if (val<min_value) { min_value = val; ptr_min = ptrs; }
24257  if (val>max_value) max_value = val;
24258  }
24259  max_val = (t)max_value;
24260  return *ptr_min;
24261  }
24262 
24264  template<typename t>
24265  const T& min_max(t& max_val) const {
24266  if (is_empty())
24267  throw CImgInstanceException(_cimg_instance
24268  "min_max(): Empty instance.",
24269  cimg_instance);
24270  const T *ptr_min = _data;
24271  T min_value = *ptr_min, max_value = min_value;
24272  cimg_for(*this,ptrs,T) {
24273  const T val = *ptrs;
24274  if (val<min_value) { min_value = val; ptr_min = ptrs; }
24275  if (val>max_value) max_value = val;
24276  }
24277  max_val = (t)max_value;
24278  return *ptr_min;
24279  }
24280 
24282 
24285  template<typename t>
24286  T& max_min(t& min_val) {
24287  if (is_empty())
24288  throw CImgInstanceException(_cimg_instance
24289  "max_min(): Empty instance.",
24290  cimg_instance);
24291  T *ptr_max = _data;
24292  T max_value = *ptr_max, min_value = max_value;
24293  cimg_for(*this,ptrs,T) {
24294  const T val = *ptrs;
24295  if (val>max_value) { max_value = val; ptr_max = ptrs; }
24296  if (val<min_value) min_value = val;
24297  }
24298  min_val = (t)min_value;
24299  return *ptr_max;
24300  }
24301 
24303  template<typename t>
24304  const T& max_min(t& min_val) const {
24305  if (is_empty())
24306  throw CImgInstanceException(_cimg_instance
24307  "max_min(): Empty instance.",
24308  cimg_instance);
24309  const T *ptr_max = _data;
24310  T max_value = *ptr_max, min_value = max_value;
24311  cimg_for(*this,ptrs,T) {
24312  const T val = *ptrs;
24313  if (val>max_value) { max_value = val; ptr_max = ptrs; }
24314  if (val<min_value) min_value = val;
24315  }
24316  min_val = (t)min_value;
24317  return *ptr_max;
24318  }
24319 
24321 
24324  T kth_smallest(const ulongT k) const {
24325  if (is_empty())
24326  throw CImgInstanceException(_cimg_instance
24327  "kth_smallest(): Empty instance.",
24328  cimg_instance);
24329  CImg<T> arr(*this,false);
24330  ulongT l = 0, ir = size() - 1;
24331  for ( ; ; ) {
24332  if (ir<=l + 1) {
24333  if (ir==l + 1 && arr[ir]<arr[l]) cimg::swap(arr[l],arr[ir]);
24334  return arr[k];
24335  } else {
24336  const ulongT mid = (l + ir)>>1;
24337  cimg::swap(arr[mid],arr[l + 1]);
24338  if (arr[l]>arr[ir]) cimg::swap(arr[l],arr[ir]);
24339  if (arr[l + 1]>arr[ir]) cimg::swap(arr[l + 1],arr[ir]);
24340  if (arr[l]>arr[l + 1]) cimg::swap(arr[l],arr[l + 1]);
24341  ulongT i = l + 1, j = ir;
24342  const T pivot = arr[l + 1];
24343  for ( ; ; ) {
24344  do ++i; while (arr[i]<pivot);
24345  do --j; while (arr[j]>pivot);
24346  if (j<i) break;
24347  cimg::swap(arr[i],arr[j]);
24348  }
24349  arr[l + 1] = arr[j];
24350  arr[j] = pivot;
24351  if (j>=k) ir = j - 1;
24352  if (j<=k) l = i;
24353  }
24354  }
24355  }
24356 
24358 
24360  T median() const {
24361  if (is_empty())
24362  throw CImgInstanceException(_cimg_instance
24363  "median(): Empty instance.",
24364  cimg_instance);
24365  const ulongT s = size();
24366  switch (s) {
24367  case 1 : return _data[0];
24368  case 2 : return cimg::median(_data[0],_data[1]);
24369  case 3 : return cimg::median(_data[0],_data[1],_data[2]);
24370  case 5 : return cimg::median(_data[0],_data[1],_data[2],_data[3],_data[4]);
24371  case 7 : return cimg::median(_data[0],_data[1],_data[2],_data[3],_data[4],_data[5],_data[6]);
24372  case 9 : return cimg::median(_data[0],_data[1],_data[2],_data[3],_data[4],_data[5],_data[6],_data[7],_data[8]);
24373  case 13 : return cimg::median(_data[0],_data[1],_data[2],_data[3],_data[4],_data[5],_data[6],_data[7],_data[8],
24374  _data[9],_data[10],_data[11],_data[12]);
24375  }
24376  const T res = kth_smallest(s>>1);
24377  return (s%2)?res:(T)((res + kth_smallest((s>>1) - 1))/2);
24378  }
24379 
24381 
24383  double product() const {
24384  if (is_empty()) return 0;
24385  double res = 1;
24386  cimg_for(*this,ptrs,T) res*=(double)*ptrs;
24387  return res;
24388  }
24389 
24391 
24393  double sum() const {
24394  double res = 0;
24395  cimg_for(*this,ptrs,T) res+=(double)*ptrs;
24396  return res;
24397  }
24398 
24400 
24402  double mean() const {
24403  double res = 0;
24404  cimg_for(*this,ptrs,T) res+=(double)*ptrs;
24405  return res/size();
24406  }
24407 
24409 
24419  double variance(const unsigned int variance_method=1) const {
24420  double foo;
24421  return variance_mean(variance_method,foo);
24422  }
24423 
24425 
24429  template<typename t>
24430  double variance_mean(const unsigned int variance_method, t& mean) const {
24431  if (is_empty())
24432  throw CImgInstanceException(_cimg_instance
24433  "variance_mean(): Empty instance.",
24434  cimg_instance);
24435 
24436  double variance = 0, average = 0;
24437  const ulongT siz = size();
24438  switch (variance_method) {
24439  case 0 : { // Least mean square (standard definition)
24440  double S = 0, S2 = 0;
24441  cimg_for(*this,ptrs,T) { const double val = (double)*ptrs; S+=val; S2+=val*val; }
24442  variance = (S2 - S*S/siz)/siz;
24443  average = S;
24444  } break;
24445  case 1 : { // Least mean square (robust definition)
24446  double S = 0, S2 = 0;
24447  cimg_for(*this,ptrs,T) { const double val = (double)*ptrs; S+=val; S2+=val*val; }
24448  variance = siz>1?(S2 - S*S/siz)/(siz - 1):0;
24449  average = S;
24450  } break;
24451  case 2 : { // Least Median of Squares (MAD)
24452  CImg<Tfloat> buf(*this,false);
24453  buf.sort();
24454  const ulongT siz2 = siz>>1;
24455  const double med_i = (double)buf[siz2];
24456  cimg_for(buf,ptrs,Tfloat) {
24457  const double val = (double)*ptrs; *ptrs = (Tfloat)cimg::abs(val - med_i); average+=val;
24458  }
24459  buf.sort();
24460  const double sig = (double)(1.4828*buf[siz2]);
24461  variance = sig*sig;
24462  } break;
24463  default : { // Least trimmed of Squares
24464  CImg<Tfloat> buf(*this,false);
24465  const ulongT siz2 = siz>>1;
24466  cimg_for(buf,ptrs,Tfloat) {
24467  const double val = (double)*ptrs; (*ptrs)=(Tfloat)((*ptrs)*val); average+=val;
24468  }
24469  buf.sort();
24470  double a = 0;
24471  const Tfloat *ptrs = buf._data;
24472  for (ulongT j = 0; j<siz2; ++j) a+=(double)*(ptrs++);
24473  const double sig = (double)(2.6477*std::sqrt(a/siz2));
24474  variance = sig*sig;
24475  }
24476  }
24477  mean = (t)(average/siz);
24478  return variance>0?variance:0;
24479  }
24480 
24482 
24490  double variance_noise(const unsigned int variance_method=2) const {
24491  if (is_empty())
24492  throw CImgInstanceException(_cimg_instance
24493  "variance_noise(): Empty instance.",
24494  cimg_instance);
24495 
24496  const ulongT siz = size();
24497  if (!siz || !_data) return 0;
24498  if (variance_method>1) { // Compute a scaled version of the Laplacian.
24499  CImg<Tdouble> tmp(*this,false);
24500  if (_depth==1) {
24501  const double cste = 1.0/std::sqrt(20.0); // Depends on how the Laplacian is computed.
24502  cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height>=262144 && _spectrum>=2))
24503  cimg_forC(*this,c) {
24504  CImg_3x3(I,T);
24505  cimg_for3x3(*this,x,y,0,c,I,T) {
24506  tmp(x,y,c) = cste*((double)Inc + (double)Ipc + (double)Icn +
24507  (double)Icp - 4*(double)Icc);
24508  }
24509  }
24510  } else {
24511  const double cste = 1.0/std::sqrt(42.0); // Depends on how the Laplacian is computed.
24512  cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=262144 && _spectrum>=2))
24513  cimg_forC(*this,c) {
24514  CImg_3x3x3(I,T);
24515  cimg_for3x3x3(*this,x,y,z,c,I,T) {
24516  tmp(x,y,z,c) = cste*(
24517  (double)Incc + (double)Ipcc + (double)Icnc + (double)Icpc +
24518  (double)Iccn + (double)Iccp - 6*(double)Iccc);
24519  }
24520  }
24521  }
24522  return tmp.variance(variance_method);
24523  }
24524 
24525  // Version that doesn't need intermediate images.
24526  double variance = 0, S = 0, S2 = 0;
24527  if (_depth==1) {
24528  const double cste = 1.0/std::sqrt(20.0);
24529  CImg_3x3(I,T);
24530  cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,T) {
24531  const double val = cste*((double)Inc + (double)Ipc +
24532  (double)Icn + (double)Icp - 4*(double)Icc);
24533  S+=val; S2+=val*val;
24534  }
24535  } else {
24536  const double cste = 1.0/std::sqrt(42.0);
24537  CImg_3x3x3(I,T);
24538  cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,T) {
24539  const double val = cste *
24540  ((double)Incc + (double)Ipcc + (double)Icnc +
24541  (double)Icpc +
24542  (double)Iccn + (double)Iccp - 6*(double)Iccc);
24543  S+=val; S2+=val*val;
24544  }
24545  }
24546  if (variance_method) variance = siz>1?(S2 - S*S/siz)/(siz - 1):0;
24547  else variance = (S2 - S*S/siz)/siz;
24548  return variance>0?variance:0;
24549  }
24550 
24552 
24555  template<typename t>
24556  double MSE(const CImg<t>& img) const {
24557  if (img.size()!=size())
24558  throw CImgArgumentException(_cimg_instance
24559  "MSE(): Instance and specified image (%u,%u,%u,%u,%p) have different dimensions.",
24560  cimg_instance,
24561  img._width,img._height,img._depth,img._spectrum,img._data);
24562  double vMSE = 0;
24563  const t* ptr2 = img._data;
24564  cimg_for(*this,ptr1,T) {
24565  const double diff = (double)*ptr1 - (double)*(ptr2++);
24566  vMSE+=diff*diff;
24567  }
24568  const ulongT siz = img.size();
24569  if (siz) vMSE/=siz;
24570  return vMSE;
24571  }
24572 
24574 
24578  template<typename t>
24579  double PSNR(const CImg<t>& img, const double max_value=255) const {
24580  const double vMSE = (double)std::sqrt(MSE(img));
24581  return (vMSE!=0)?(double)(20*std::log10(max_value/vMSE)):(double)(cimg::type<double>::max());
24582  }
24583 
24585 
24594  double eval(const char *const expression,
24595  const double x=0, const double y=0, const double z=0, const double c=0,
24596  const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) {
24597  return _eval(this,expression,x,y,z,c,list_inputs,list_outputs);
24598  }
24599 
24601  double eval(const char *const expression,
24602  const double x=0, const double y=0, const double z=0, const double c=0,
24603  const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const {
24604  return _eval(0,expression,x,y,z,c,list_inputs,list_outputs);
24605  }
24606 
24607  double _eval(CImg<T> *const img_output, const char *const expression,
24608  const double x, const double y, const double z, const double c,
24609  const CImgList<T> *const list_inputs, CImgList<T> *const list_outputs) const {
24610  if (!expression || !*expression) return 0;
24611  if (!expression[1]) switch (*expression) { // Single-char optimization.
24612  case 'w' : return (double)_width;
24613  case 'h' : return (double)_height;
24614  case 'd' : return (double)_depth;
24615  case 's' : return (double)_spectrum;
24616  case 'r' : return (double)_is_shared;
24617  }
24618  _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' ||
24619  *expression=='*' || *expression==':'),"eval",
24620  *this,img_output,list_inputs,list_outputs,false);
24621  const double val = mp(x,y,z,c);
24622  mp.end();
24623  return val;
24624  }
24625 
24627 
24638  template<typename t>
24639  void eval(CImg<t> &output, const char *const expression,
24640  const double x=0, const double y=0, const double z=0, const double c=0,
24641  const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) {
24642  _eval(output,this,expression,x,y,z,c,list_inputs,list_outputs);
24643  }
24644 
24646  template<typename t>
24647  void eval(CImg<t>& output, const char *const expression,
24648  const double x=0, const double y=0, const double z=0, const double c=0,
24649  const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const {
24650  _eval(output,0,expression,x,y,z,c,list_inputs,list_outputs);
24651  }
24652 
24653  template<typename t>
24654  void _eval(CImg<t>& output, CImg<T> *const img_output, const char *const expression,
24655  const double x, const double y, const double z, const double c,
24656  const CImgList<T> *const list_inputs, CImgList<T> *const list_outputs) const {
24657  if (!expression || !*expression) { output.assign(1); *output = 0; }
24658  if (!expression[1]) switch (*expression) { // Single-char optimization.
24659  case 'w' : output.assign(1); *output = (t)_width; break;
24660  case 'h' : output.assign(1); *output = (t)_height; break;
24661  case 'd' : output.assign(1); *output = (t)_depth; break;
24662  case 's' : output.assign(1); *output = (t)_spectrum; break;
24663  case 'r' : output.assign(1); *output = (t)_is_shared; break;
24664  }
24665  _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' ||
24666  *expression=='*' || *expression==':'),"eval",
24667  *this,img_output,list_inputs,list_outputs,false);
24668  output.assign(1,std::max(1U,mp.result_dim));
24669  mp(x,y,z,c,output._data);
24670  mp.end();
24671  }
24672 
24674 
24680  template<typename t>
24681  CImg<doubleT> eval(const char *const expression, const CImg<t>& xyzc,
24682  const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) {
24683  return _eval(this,expression,xyzc,list_inputs,list_outputs);
24684  }
24685 
24687  template<typename t>
24688  CImg<doubleT> eval(const char *const expression, const CImg<t>& xyzc,
24689  const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const {
24690  return _eval(0,expression,xyzc,list_inputs,list_outputs);
24691  }
24692 
24693  template<typename t>
24694  CImg<doubleT> _eval(CImg<T> *const output, const char *const expression, const CImg<t>& xyzc,
24695  const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const {
24696  CImg<doubleT> res(1,xyzc.size()/4);
24697  if (!expression || !*expression) return res.fill(0);
24698  _cimg_math_parser mp(expression,"eval",*this,output,list_inputs,list_outputs,false);
24699 #ifdef cimg_use_openmp
24700  cimg_pragma_openmp(parallel if (res._height>=512))
24701  {
24702  _cimg_math_parser
24703  _mp = omp_get_thread_num()?mp:_cimg_math_parser(),
24704  &lmp = omp_get_thread_num()?_mp:mp;
24705  cimg_pragma_openmp(for)
24706  for (unsigned int i = 0; i<res._height; ++i) {
24707  const unsigned int i4 = 4*i;
24708  const double
24709  x = (double)xyzc[i4], y = (double)xyzc[i4 + 1],
24710  z = (double)xyzc[i4 + 2], c = (double)xyzc[i4 + 3];
24711  res[i] = lmp(x,y,z,c);
24712  }
24713  }
24714 #else
24715  const t *ps = xyzc._data;
24716  cimg_for(res,pd,double) {
24717  const double x = (double)*(ps++), y = (double)*(ps++), z = (double)*(ps++), c = (double)*(ps++);
24718  *pd = mp(x,y,z,c);
24719  }
24720 #endif
24721  mp.end();
24722  return res;
24723  }
24724 
24726  /*
24727  \param variance_method Method used to compute the variance (see variance(const unsigned int) const).
24728  \return Statistics vector as
24729  <tt>[min, max, mean, variance, xmin, ymin, zmin, cmin, xmax, ymax, zmax, cmax, sum, product]</tt>.
24730  **/
24731  CImg<Tdouble> get_stats(const unsigned int variance_method=1) const {
24732  if (is_empty()) return CImg<doubleT>();
24733  const T *const p_end = end(), *pm = _data, *pM = _data;
24734  double S = 0, S2 = 0, P = 1;
24735  const ulongT siz = size();
24736  T m = *pm, M = *pM;
24737 
24738  cimg_pragma_openmp(parallel reduction(+:S,S2) reduction(*:P) cimg_openmp_if(siz>=131072)) {
24739  const T *lpm = _data, *lpM = _data;
24740  T lm = *lpm, lM = *lpM;
24741  cimg_pragma_openmp(for)
24742  for (const T *ptrs = _data; ptrs<p_end; ++ptrs) {
24743  const T val = *ptrs;
24744  const double _val = (double)val;
24745  if (val<lm) { lm = val; lpm = ptrs; }
24746  if (val>lM) { lM = val; lpM = ptrs; }
24747  S+=_val;
24748  S2+=_val*_val;
24749  P*=_val;
24750  }
24751  cimg_pragma_openmp(critical(get_stats)) {
24752  if (lm<m || (lm==m && lpm<pm)) { m = lm; pm = lpm; }
24753  if (lM>M || (lM==M && lpM<pM)) { M = lM; pM = lpM; }
24754  }
24755  }
24756 
24757  const double
24758  mean_value = S/siz,
24759  _variance_value = variance_method==0?(S2 - S*S/siz)/siz:
24760  (variance_method==1?(siz>1?(S2 - S*S/siz)/(siz - 1):0):
24761  variance(variance_method)),
24762  variance_value = _variance_value>0?_variance_value:0;
24763  int
24764  xm = 0, ym = 0, zm = 0, cm = 0,
24765  xM = 0, yM = 0, zM = 0, cM = 0;
24766  contains(*pm,xm,ym,zm,cm);
24767  contains(*pM,xM,yM,zM,cM);
24768  return CImg<Tdouble>(1,14).fill((double)m,(double)M,mean_value,variance_value,
24769  (double)xm,(double)ym,(double)zm,(double)cm,
24770  (double)xM,(double)yM,(double)zM,(double)cM,
24771  S,P);
24772  }
24773 
24775  CImg<T>& stats(const unsigned int variance_method=1) {
24776  return get_stats(variance_method).move_to(*this);
24777  }
24778 
24780  //-------------------------------------
24781  //
24783 
24784  //-------------------------------------
24785 
24787 
24794  double magnitude(const int magnitude_type=2) const {
24795  if (is_empty())
24796  throw CImgInstanceException(_cimg_instance
24797  "magnitude(): Empty instance.",
24798  cimg_instance);
24799  double res = 0;
24800  switch (magnitude_type) {
24801  case -1 : {
24802  cimg_for(*this,ptrs,T) { const double val = (double)cimg::abs(*ptrs); if (val>res) res = val; }
24803  } break;
24804  case 1 : {
24805  cimg_for(*this,ptrs,T) res+=(double)cimg::abs(*ptrs);
24806  } break;
24807  default : {
24808  cimg_for(*this,ptrs,T) res+=(double)cimg::sqr(*ptrs);
24809  res = (double)std::sqrt(res);
24810  }
24811  }
24812  return res;
24813  }
24814 
24816 
24818  double trace() const {
24819  if (is_empty())
24820  throw CImgInstanceException(_cimg_instance
24821  "trace(): Empty instance.",
24822  cimg_instance);
24823  double res = 0;
24824  cimg_forX(*this,k) res+=(double)(*this)(k,k);
24825  return res;
24826  }
24827 
24829 
24831  double det() const {
24832  if (is_empty() || _width!=_height || _depth!=1 || _spectrum!=1)
24833  throw CImgInstanceException(_cimg_instance
24834  "det(): Instance is not a square matrix.",
24835  cimg_instance);
24836 
24837  switch (_width) {
24838  case 1 : return (double)((*this)(0,0));
24839  case 2 : return (double)((*this)(0,0))*(double)((*this)(1,1)) - (double)((*this)(0,1))*(double)((*this)(1,0));
24840  case 3 : {
24841  const double
24842  a = (double)_data[0], d = (double)_data[1], g = (double)_data[2],
24843  b = (double)_data[3], e = (double)_data[4], h = (double)_data[5],
24844  c = (double)_data[6], f = (double)_data[7], i = (double)_data[8];
24845  return i*a*e - a*h*f - i*b*d + b*g*f + c*d*h - c*g*e;
24846  }
24847  default : {
24848  CImg<Tfloat> lu(*this,false);
24849  CImg<uintT> indx;
24850  bool d;
24851  lu._LU(indx,d);
24852  double res = d?(double)1:(double)-1;
24853  cimg_forX(lu,i) res*=lu(i,i);
24854  return res;
24855  }
24856  }
24857  }
24858 
24860 
24863  template<typename t>
24864  double dot(const CImg<t>& img) const {
24865  if (is_empty())
24866  throw CImgInstanceException(_cimg_instance
24867  "dot(): Empty instance.",
24868  cimg_instance);
24869  if (!img)
24870  throw CImgArgumentException(_cimg_instance
24871  "dot(): Empty specified image.",
24872  cimg_instance);
24873 
24874  const ulongT nb = std::min(size(),img.size());
24875  double res = 0;
24876  for (ulongT off = 0; off<nb; ++off) res+=(double)_data[off]*(double)img[off];
24877  return res;
24878  }
24879 
24881 
24886  CImg<T> get_vector_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {
24887  CImg<T> res;
24888  if (res._height!=_spectrum) res.assign(1,_spectrum);
24889  const ulongT whd = (ulongT)_width*_height*_depth;
24890  const T *ptrs = data(x,y,z);
24891  T *ptrd = res._data;
24892  cimg_forC(*this,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
24893  return res;
24894  }
24895 
24897 
24903  CImg<T> get_matrix_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const {
24904  const int n = (int)std::sqrt((double)_spectrum);
24905  const T *ptrs = data(x,y,z,0);
24906  const ulongT whd = (ulongT)_width*_height*_depth;
24907  CImg<T> res(n,n);
24908  T *ptrd = res._data;
24909  cimg_forC(*this,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
24910  return res;
24911  }
24912 
24914 
24919  CImg<T> get_tensor_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {
24920  const T *ptrs = data(x,y,z,0);
24921  const ulongT whd = (ulongT)_width*_height*_depth;
24922  if (_spectrum==6)
24923  return tensor(*ptrs,*(ptrs + whd),*(ptrs + 2*whd),*(ptrs + 3*whd),*(ptrs + 4*whd),*(ptrs + 5*whd));
24924  if (_spectrum==3)
24925  return tensor(*ptrs,*(ptrs + whd),*(ptrs + 2*whd));
24926  return tensor(*ptrs);
24927  }
24928 
24930 
24936  template<typename t>
24937  CImg<T>& set_vector_at(const CImg<t>& vec, const unsigned int x, const unsigned int y=0, const unsigned int z=0) {
24938  if (x<_width && y<_height && z<_depth) {
24939  const t *ptrs = vec._data;
24940  const ulongT whd = (ulongT)_width*_height*_depth;
24941  T *ptrd = data(x,y,z);
24942  for (unsigned int k = std::min((unsigned int)vec.size(),_spectrum); k; --k) {
24943  *ptrd = (T)*(ptrs++); ptrd+=whd;
24944  }
24945  }
24946  return *this;
24947  }
24948 
24950 
24956  template<typename t>
24957  CImg<T>& set_matrix_at(const CImg<t>& mat, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
24958  return set_vector_at(mat,x,y,z);
24959  }
24960 
24962 
24968  template<typename t>
24969  CImg<T>& set_tensor_at(const CImg<t>& ten, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
24970  T *ptrd = data(x,y,z,0);
24971  const ulongT siz = (ulongT)_width*_height*_depth;
24972  if (ten._height==2) {
24973  *ptrd = (T)ten[0]; ptrd+=siz;
24974  *ptrd = (T)ten[1]; ptrd+=siz;
24975  *ptrd = (T)ten[3];
24976  }
24977  else {
24978  *ptrd = (T)ten[0]; ptrd+=siz;
24979  *ptrd = (T)ten[1]; ptrd+=siz;
24980  *ptrd = (T)ten[2]; ptrd+=siz;
24981  *ptrd = (T)ten[4]; ptrd+=siz;
24982  *ptrd = (T)ten[5]; ptrd+=siz;
24983  *ptrd = (T)ten[8];
24984  }
24985  return *this;
24986  }
24987 
24989 
24993  return unroll('y');
24994  }
24995 
24998  return get_unroll('y');
24999  }
25000 
25002 
25005  const ulongT siz = size();
25006  switch (siz) {
25007  case 1 : break;
25008  case 4 : _width = _height = 2; break;
25009  case 9 : _width = _height = 3; break;
25010  case 16 : _width = _height = 4; break;
25011  case 25 : _width = _height = 5; break;
25012  case 36 : _width = _height = 6; break;
25013  case 49 : _width = _height = 7; break;
25014  case 64 : _width = _height = 8; break;
25015  case 81 : _width = _height = 9; break;
25016  case 100 : _width = _height = 10; break;
25017  default : {
25018  ulongT i = 11, i2 = i*i;
25019  while (i2<siz) { i2+=2*i + 1; ++i; }
25020  if (i2==siz) _width = _height = i;
25021  else throw CImgInstanceException(_cimg_instance
25022  "matrix(): Invalid instance size %u (should be a square integer).",
25023  cimg_instance,
25024  siz);
25025  }
25026  }
25027  return *this;
25028  }
25029 
25032  return (+*this).matrix();
25033  }
25034 
25036 
25039  return get_tensor().move_to(*this);
25040  }
25041 
25044  CImg<T> res;
25045  const ulongT siz = size();
25046  switch (siz) {
25047  case 1 : break;
25048  case 3 :
25049  res.assign(2,2);
25050  res(0,0) = (*this)(0);
25051  res(1,0) = res(0,1) = (*this)(1);
25052  res(1,1) = (*this)(2);
25053  break;
25054  case 6 :
25055  res.assign(3,3);
25056  res(0,0) = (*this)(0);
25057  res(1,0) = res(0,1) = (*this)(1);
25058  res(2,0) = res(0,2) = (*this)(2);
25059  res(1,1) = (*this)(3);
25060  res(2,1) = res(1,2) = (*this)(4);
25061  res(2,2) = (*this)(5);
25062  break;
25063  default :
25064  throw CImgInstanceException(_cimg_instance
25065  "tensor(): Invalid instance size (does not define a 1x1, 2x2 or 3x3 tensor).",
25066  cimg_instance);
25067  }
25068  return res;
25069  }
25070 
25072 
25076  return get_diagonal().move_to(*this);
25077  }
25078 
25081  if (is_empty()) return *this;
25082  const unsigned int siz = (unsigned int)size();
25083  CImg<T> res(siz,siz,1,1,0);
25084  cimg_foroff(*this,off) res((unsigned int)off,(unsigned int)off) = (*this)[off];
25085  return res;
25086  }
25087 
25089 
25094  return identity_matrix(std::max(_width,_height)).move_to(*this);
25095  }
25096 
25099  return identity_matrix(std::max(_width,_height));
25100  }
25101 
25103 
25107  CImg<T>& sequence(const T& a0, const T& a1) {
25108  if (is_empty()) return *this;
25109  const ulongT siz = size() - 1;
25110  T* ptr = _data;
25111  if (siz) {
25112  const double delta = (double)a1 - (double)a0;
25113  cimg_foroff(*this,l) *(ptr++) = (T)(a0 + delta*l/siz);
25114  } else *ptr = a0;
25115  return *this;
25116  }
25117 
25119  CImg<T> get_sequence(const T& a0, const T& a1) const {
25120  return (+*this).sequence(a0,a1);
25121  }
25122 
25124 
25128  if (_width==1) { _width = _height; _height = 1; return *this; }
25129  if (_height==1) { _height = _width; _width = 1; return *this; }
25130  if (_width==_height) {
25131  cimg_forYZC(*this,y,z,c) for (int x = y; x<width(); ++x) cimg::swap((*this)(x,y,z,c),(*this)(y,x,z,c));
25132  return *this;
25133  }
25134  return get_transpose().move_to(*this);
25135  }
25136 
25139  return get_permute_axes("yxzc");
25140  }
25141 
25143 
25147  template<typename t>
25148  CImg<T>& cross(const CImg<t>& img) {
25149  if (_width!=1 || _height<3 || img._width!=1 || img._height<3)
25150  throw CImgInstanceException(_cimg_instance
25151  "cross(): Instance and/or specified image (%u,%u,%u,%u,%p) are not 3d vectors.",
25152  cimg_instance,
25153  img._width,img._height,img._depth,img._spectrum,img._data);
25154 
25155  const T x = (*this)[0], y = (*this)[1], z = (*this)[2];
25156  (*this)[0] = (T)(y*img[2] - z*img[1]);
25157  (*this)[1] = (T)(z*img[0] - x*img[2]);
25158  (*this)[2] = (T)(x*img[1] - y*img[0]);
25159  return *this;
25160  }
25161 
25163  template<typename t>
25164  CImg<_cimg_Tt> get_cross(const CImg<t>& img) const {
25165  return CImg<_cimg_Tt>(*this).cross(img);
25166  }
25167 
25169 
25174  CImg<T>& invert(const bool use_LU=true) {
25175  if (_width!=_height || _depth!=1 || _spectrum!=1)
25176  throw CImgInstanceException(_cimg_instance
25177  "invert(): Instance is not a square matrix.",
25178  cimg_instance);
25179 #ifdef cimg_use_lapack
25180  int INFO = (int)use_LU, N = _width, LWORK = 4*N, *const IPIV = new int[N];
25181  Tfloat
25182  *const lapA = new Tfloat[N*N],
25183  *const WORK = new Tfloat[LWORK];
25184  cimg_forXY(*this,k,l) lapA[k*N + l] = (Tfloat)((*this)(k,l));
25185  cimg::getrf(N,lapA,IPIV,INFO);
25186  if (INFO)
25187  cimg::warn(_cimg_instance
25188  "invert(): LAPACK function dgetrf_() returned error code %d.",
25189  cimg_instance,
25190  INFO);
25191  else {
25192  cimg::getri(N,lapA,IPIV,WORK,LWORK,INFO);
25193  if (INFO)
25194  cimg::warn(_cimg_instance
25195  "invert(): LAPACK function dgetri_() returned error code %d.",
25196  cimg_instance,
25197  INFO);
25198  }
25199  if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)(lapA[k*N + l]); else fill(0);
25200  delete[] IPIV; delete[] lapA; delete[] WORK;
25201 #else
25202  const double dete = _width>3?-1.0:det();
25203  if (dete!=0.0 && _width==2) {
25204  const double
25205  a = _data[0], c = _data[1],
25206  b = _data[2], d = _data[3];
25207  _data[0] = (T)(d/dete); _data[1] = (T)(-c/dete);
25208  _data[2] = (T)(-b/dete); _data[3] = (T)(a/dete);
25209  } else if (dete!=0.0 && _width==3) {
25210  const double
25211  a = _data[0], d = _data[1], g = _data[2],
25212  b = _data[3], e = _data[4], h = _data[5],
25213  c = _data[6], f = _data[7], i = _data[8];
25214  _data[0] = (T)((i*e - f*h)/dete), _data[1] = (T)((g*f - i*d)/dete), _data[2] = (T)((d*h - g*e)/dete);
25215  _data[3] = (T)((h*c - i*b)/dete), _data[4] = (T)((i*a - c*g)/dete), _data[5] = (T)((g*b - a*h)/dete);
25216  _data[6] = (T)((b*f - e*c)/dete), _data[7] = (T)((d*c - a*f)/dete), _data[8] = (T)((a*e - d*b)/dete);
25217  } else {
25218  if (use_LU) { // LU-based inverse computation
25219  CImg<Tfloat> A(*this,false), indx, col(1,_width);
25220  bool d;
25221  A._LU(indx,d);
25222  cimg_forX(*this,j) {
25223  col.fill(0);
25224  col(j) = 1;
25225  col._solve(A,indx);
25226  cimg_forX(*this,i) (*this)(j,i) = (T)col(i);
25227  }
25228  } else { // SVD-based inverse computation
25229  CImg<Tfloat> U(_width,_width), S(1,_width), V(_width,_width);
25230  SVD(U,S,V,false);
25231  U.transpose();
25232  cimg_forY(S,k) if (S[k]!=0) S[k]=1/S[k];
25233  S.diagonal();
25234  *this = V*S*U;
25235  }
25236  }
25237 #endif
25238  return *this;
25239  }
25240 
25242  CImg<Tfloat> get_invert(const bool use_LU=true) const {
25243  return CImg<Tfloat>(*this,false).invert(use_LU);
25244  }
25245 
25247 
25250  return get_pseudoinvert().move_to(*this);
25251  }
25252 
25255  CImg<Tfloat> U, S, V;
25256  SVD(U,S,V);
25257  const Tfloat tolerance = (sizeof(Tfloat)<=4?5.96e-8f:1.11e-16f)*std::max(_width,_height)*S.max();
25258  cimg_forX(V,x) {
25259  const Tfloat s = S(x), invs = s>tolerance?1/s:0;
25260  cimg_forY(V,y) V(x,y)*=invs;
25261  }
25262  return V*U.transpose();
25263  }
25264 
25266 
25270  template<typename t>
25271  CImg<T>& solve(const CImg<t>& A) {
25272  if (_depth!=1 || _spectrum!=1 || _height!=A._height || A._depth!=1 || A._spectrum!=1)
25273  throw CImgArgumentException(_cimg_instance
25274  "solve(): Instance and specified matrix (%u,%u,%u,%u,%p) have "
25275  "incompatible dimensions.",
25276  cimg_instance,
25277  A._width,A._height,A._depth,A._spectrum,A._data);
25278  typedef _cimg_Ttfloat Ttfloat;
25279  if (A._width==A._height) { // Classical linear system
25280  if (_width!=1) {
25281  CImg<T> res(_width,A._width);
25282  cimg_forX(*this,i) res.draw_image(i,get_column(i).solve(A));
25283  return res.move_to(*this);
25284  }
25285 #ifdef cimg_use_lapack
25286  char TRANS = 'N';
25287  int INFO, N = _height, LWORK = 4*N, *const IPIV = new int[N];
25288  Ttfloat
25289  *const lapA = new Ttfloat[N*N],
25290  *const lapB = new Ttfloat[N],
25291  *const WORK = new Ttfloat[LWORK];
25292  cimg_forXY(A,k,l) lapA[k*N + l] = (Ttfloat)(A(k,l));
25293  cimg_forY(*this,i) lapB[i] = (Ttfloat)((*this)(i));
25294  cimg::getrf(N,lapA,IPIV,INFO);
25295  if (INFO)
25296  cimg::warn(_cimg_instance
25297  "solve(): LAPACK library function dgetrf_() returned error code %d.",
25298  cimg_instance,
25299  INFO);
25300 
25301  if (!INFO) {
25302  cimg::getrs(TRANS,N,lapA,IPIV,lapB,INFO);
25303  if (INFO)
25304  cimg::warn(_cimg_instance
25305  "solve(): LAPACK library function dgetrs_() returned error code %d.",
25306  cimg_instance,
25307  INFO);
25308  }
25309  if (!INFO) cimg_forY(*this,i) (*this)(i) = (T)(lapB[i]); else fill(0);
25310  delete[] IPIV; delete[] lapA; delete[] lapB; delete[] WORK;
25311 #else
25312  CImg<Ttfloat> lu(A,false);
25313  CImg<Ttfloat> indx;
25314  bool d;
25315  lu._LU(indx,d);
25316  _solve(lu,indx);
25317 #endif
25318  } else { // Least-square solution for non-square systems.
25319 #ifdef cimg_use_lapack
25320  if (_width!=1) {
25321  CImg<T> res(_width,A._width);
25322  cimg_forX(*this,i) res.draw_image(i,get_column(i).solve(A));
25323  return res.move_to(*this);
25324  }
25325  char TRANS = 'N';
25326  int INFO, N = A._width, M = A._height, LWORK = -1, LDA = M, LDB = M, NRHS = _width;
25327  Ttfloat WORK_QUERY;
25328  Ttfloat
25329  * const lapA = new Ttfloat[M*N],
25330  * const lapB = new Ttfloat[M*NRHS];
25331  cimg::sgels(TRANS, M, N, NRHS, lapA, LDA, lapB, LDB, &WORK_QUERY, LWORK, INFO);
25332  LWORK = (int) WORK_QUERY;
25333  Ttfloat *const WORK = new Ttfloat[LWORK];
25334  cimg_forXY(A,k,l) lapA[k*M + l] = (Ttfloat)(A(k,l));
25335  cimg_forXY(*this,k,l) lapB[k*M + l] = (Ttfloat)((*this)(k,l));
25336  cimg::sgels(TRANS, M, N, NRHS, lapA, LDA, lapB, LDB, WORK, LWORK, INFO);
25337  if (INFO != 0)
25338  cimg::warn(_cimg_instance
25339  "solve(): LAPACK library function sgels() returned error code %d.",
25340  cimg_instance,
25341  INFO);
25342  assign(NRHS, N);
25343  if (!INFO)
25344  cimg_forXY(*this,k,l) (*this)(k,l) = (T)lapB[k*M + l];
25345  else
25346  assign(A.get_pseudoinvert()*(*this));
25347  delete[] lapA; delete[] lapB; delete[] WORK;
25348 #else
25349  assign(A.get_pseudoinvert()*(*this));
25350 #endif
25351  }
25352  return *this;
25353  }
25354 
25356  template<typename t>
25358  return CImg<_cimg_Ttfloat>(*this,false).solve(A);
25359  }
25360 
25361  template<typename t, typename ti>
25362  CImg<T>& _solve(const CImg<t>& A, const CImg<ti>& indx) {
25363  typedef _cimg_Ttfloat Ttfloat;
25364  const int N = (int)size();
25365  int ii = -1;
25366  Ttfloat sum;
25367  for (int i = 0; i<N; ++i) {
25368  const int ip = (int)indx[i];
25369  Ttfloat sum = (*this)(ip);
25370  (*this)(ip) = (*this)(i);
25371  if (ii>=0) for (int j = ii; j<=i - 1; ++j) sum-=A(j,i)*(*this)(j);
25372  else if (sum!=0) ii = i;
25373  (*this)(i) = (T)sum;
25374  }
25375  for (int i = N - 1; i>=0; --i) {
25376  sum = (*this)(i);
25377  for (int j = i + 1; j<N; ++j) sum-=A(j,i)*(*this)(j);
25378  (*this)(i) = (T)(sum/A(i,i));
25379  }
25380  return *this;
25381  }
25382 
25384 
25390  template<typename t>
25392  const unsigned int siz = (unsigned int)size();
25393  if (A._width!=3 || A._height!=siz)
25394  throw CImgArgumentException(_cimg_instance
25395  "solve_tridiagonal(): Instance and tridiagonal matrix "
25396  "(%u,%u,%u,%u,%p) have incompatible dimensions.",
25397  cimg_instance,
25398  A._width,A._height,A._depth,A._spectrum,A._data);
25399  typedef _cimg_Ttfloat Ttfloat;
25400  const Ttfloat epsilon = 1e-4f;
25401  CImg<Ttfloat> B = A.get_column(1), V(*this,false);
25402  for (int i = 1; i<(int)siz; ++i) {
25403  const Ttfloat m = A(0,i)/(B[i - 1]?B[i - 1]:epsilon);
25404  B[i] -= m*A(2,i - 1);
25405  V[i] -= m*V[i - 1];
25406  }
25407  (*this)[siz - 1] = (T)(V[siz - 1]/(B[siz - 1]?B[siz - 1]:epsilon));
25408  for (int i = (int)siz - 2; i>=0; --i) (*this)[i] = (T)((V[i] - A(2,i)*(*this)[i + 1])/(B[i]?B[i]:epsilon));
25409  return *this;
25410  }
25411 
25413  template<typename t>
25415  return CImg<_cimg_Ttfloat>(*this,false).solve_tridiagonal(A);
25416  }
25417 
25419 
25423  template<typename t>
25424  const CImg<T>& eigen(CImg<t>& val, CImg<t> &vec) const {
25425  if (is_empty()) { val.assign(); vec.assign(); }
25426  else {
25427  if (_width!=_height || _depth>1 || _spectrum>1)
25428  throw CImgInstanceException(_cimg_instance
25429  "eigen(): Instance is not a square matrix.",
25430  cimg_instance);
25431 
25432  if (val.size()<(ulongT)_width) val.assign(1,_width);
25433  if (vec.size()<(ulongT)_width*_width) vec.assign(_width,_width);
25434  switch (_width) {
25435  case 1 : { val[0] = (t)(*this)[0]; vec[0] = (t)1; } break;
25436  case 2 : {
25437  const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a + d;
25438  double f = e*e - 4*(a*d - b*c);
25439  if (f<0)
25440  cimg::warn(_cimg_instance
25441  "eigen(): Complex eigenvalues found.",
25442  cimg_instance);
25443 
25444  f = std::sqrt(f);
25445  const double
25446  l1 = 0.5*(e - f),
25447  l2 = 0.5*(e + f),
25448  b2 = b*b,
25449  norm1 = std::sqrt(cimg::sqr(l2 - a) + b2),
25450  norm2 = std::sqrt(cimg::sqr(l1 - a) + b2);
25451  val[0] = (t)l2;
25452  val[1] = (t)l1;
25453  if (norm1>0) { vec(0,0) = (t)(b/norm1); vec(0,1) = (t)((l2 - a)/norm1); } else { vec(0,0) = 1; vec(0,1) = 0; }
25454  if (norm2>0) { vec(1,0) = (t)(b/norm2); vec(1,1) = (t)((l1 - a)/norm2); } else { vec(1,0) = 1; vec(1,1) = 0; }
25455  } break;
25456  default :
25457  throw CImgInstanceException(_cimg_instance
25458  "eigen(): Eigenvalues computation of general matrices is limited "
25459  "to 2x2 matrices.",
25460  cimg_instance);
25461  }
25462  }
25463  return *this;
25464  }
25465 
25467 
25471  CImgList<Tfloat> res(2);
25472  eigen(res[0],res[1]);
25473  return res;
25474  }
25475 
25477 
25481  template<typename t>
25482  const CImg<T>& symmetric_eigen(CImg<t>& val, CImg<t>& vec) const {
25483  if (is_empty()) { val.assign(); vec.assign(); }
25484  else {
25485 #ifdef cimg_use_lapack
25486  char JOB = 'V', UPLO = 'U';
25487  int N = _width, LWORK = 4*N, INFO;
25488  Tfloat
25489  *const lapA = new Tfloat[N*N],
25490  *const lapW = new Tfloat[N],
25491  *const WORK = new Tfloat[LWORK];
25492  cimg_forXY(*this,k,l) lapA[k*N + l] = (Tfloat)((*this)(k,l));
25493  cimg::syev(JOB,UPLO,N,lapA,lapW,WORK,LWORK,INFO);
25494  if (INFO)
25495  cimg::warn(_cimg_instance
25496  "symmetric_eigen(): LAPACK library function dsyev_() returned error code %d.",
25497  cimg_instance,
25498  INFO);
25499 
25500  val.assign(1,N);
25501  vec.assign(N,N);
25502  if (!INFO) {
25503  cimg_forY(val,i) val(i) = (T)lapW[N - 1 -i];
25504  cimg_forXY(vec,k,l) vec(k,l) = (T)(lapA[(N - 1 - k)*N + l]);
25505  } else { val.fill(0); vec.fill(0); }
25506  delete[] lapA; delete[] lapW; delete[] WORK;
25507 #else
25508  if (_width!=_height || _depth>1 || _spectrum>1)
25509  throw CImgInstanceException(_cimg_instance
25510  "eigen(): Instance is not a square matrix.",
25511  cimg_instance);
25512 
25513  val.assign(1,_width);
25514  if (vec._data) vec.assign(_width,_width);
25515  if (_width<3) {
25516  eigen(val,vec);
25517  if (_width==2) { vec[1] = -vec[2]; vec[3] = vec[0]; } // Force orthogonality for 2x2 matrices.
25518  return *this;
25519  }
25520  CImg<t> V(_width,_width);
25521  Tfloat M = 0, m = (Tfloat)min_max(M), maxabs = cimg::max((Tfloat)1,cimg::abs(m),cimg::abs(M));
25522  (CImg<Tfloat>(*this,false)/=maxabs).SVD(vec,val,V,false);
25523  if (maxabs!=1) val*=maxabs;
25524 
25525  bool is_ambiguous = false;
25526  float eig = 0;
25527  cimg_forY(val,p) { // check for ambiguous cases.
25528  if (val[p]>eig) eig = (float)val[p];
25529  t scal = 0;
25530  cimg_forY(vec,y) scal+=vec(p,y)*V(p,y);
25531  if (cimg::abs(scal)<0.9f) is_ambiguous = true;
25532  if (scal<0) val[p] = -val[p];
25533  }
25534  if (is_ambiguous) {
25535  ++(eig*=2);
25536  SVD(vec,val,V,false,40,eig);
25537  val-=eig;
25538  }
25539  CImg<intT> permutations; // sort eigenvalues in decreasing order
25540  CImg<t> tmp(_width);
25541  val.sort(permutations,false);
25542  cimg_forY(vec,k) {
25543  cimg_forY(permutations,y) tmp(y) = vec(permutations(y),k);
25544  std::memcpy(vec.data(0,k),tmp._data,sizeof(t)*_width);
25545  }
25546 #endif
25547  }
25548  return *this;
25549  }
25550 
25552 
25557  CImgList<Tfloat> res(2);
25558  symmetric_eigen(res[0],res[1]);
25559  return res;
25560  }
25561 
25563 
25567  template<typename t>
25568  CImg<T>& sort(CImg<t>& permutations, const bool is_increasing=true) {
25569  permutations.assign(_width,_height,_depth,_spectrum);
25570  if (is_empty()) return *this;
25571  cimg_foroff(permutations,off) permutations[off] = (t)off;
25572  return _quicksort(0,size() - 1,permutations,is_increasing,true);
25573  }
25574 
25576  template<typename t>
25577  CImg<T> get_sort(CImg<t>& permutations, const bool is_increasing=true) const {
25578  return (+*this).sort(permutations,is_increasing);
25579  }
25580 
25582 
25591  CImg<T>& sort(const bool is_increasing=true, const char axis=0) {
25592  if (is_empty()) return *this;
25593  CImg<uintT> perm;
25594  switch (cimg::lowercase(axis)) {
25595  case 0 :
25596  _quicksort(0,size() - 1,perm,is_increasing,false);
25597  break;
25598  case 'x' : {
25599  perm.assign(_width);
25600  get_crop(0,0,0,0,_width - 1,0,0,0).sort(perm,is_increasing);
25601  CImg<T> img(*this,false);
25602  cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(perm[x],y,z,c);
25603  } break;
25604  case 'y' : {
25605  perm.assign(_height);
25606  get_crop(0,0,0,0,0,_height - 1,0,0).sort(perm,is_increasing);
25607  CImg<T> img(*this,false);
25608  cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(x,perm[y],z,c);
25609  } break;
25610  case 'z' : {
25611  perm.assign(_depth);
25612  get_crop(0,0,0,0,0,0,_depth - 1,0).sort(perm,is_increasing);
25613  CImg<T> img(*this,false);
25614  cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(x,y,perm[z],c);
25615  } break;
25616  case 'c' : {
25617  perm.assign(_spectrum);
25618  get_crop(0,0,0,0,0,0,0,_spectrum - 1).sort(perm,is_increasing);
25619  CImg<T> img(*this,false);
25620  cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(x,y,z,perm[c]);
25621  } break;
25622  default :
25623  throw CImgArgumentException(_cimg_instance
25624  "sort(): Invalid specified axis '%c' "
25625  "(should be { x | y | z | c }).",
25626  cimg_instance,axis);
25627  }
25628  return *this;
25629  }
25630 
25632  CImg<T> get_sort(const bool is_increasing=true, const char axis=0) const {
25633  return (+*this).sort(is_increasing,axis);
25634  }
25635 
25636  template<typename t>
25637  CImg<T>& _quicksort(const long indm, const long indM, CImg<t>& permutations,
25638  const bool is_increasing, const bool is_permutations) {
25639  if (indm<indM) {
25640  const long mid = (indm + indM)/2;
25641  if (is_increasing) {
25642  if ((*this)[indm]>(*this)[mid]) {
25643  cimg::swap((*this)[indm],(*this)[mid]);
25644  if (is_permutations) cimg::swap(permutations[indm],permutations[mid]);
25645  }
25646  if ((*this)[mid]>(*this)[indM]) {
25647  cimg::swap((*this)[indM],(*this)[mid]);
25648  if (is_permutations) cimg::swap(permutations[indM],permutations[mid]);
25649  }
25650  if ((*this)[indm]>(*this)[mid]) {
25651  cimg::swap((*this)[indm],(*this)[mid]);
25652  if (is_permutations) cimg::swap(permutations[indm],permutations[mid]);
25653  }
25654  } else {
25655  if ((*this)[indm]<(*this)[mid]) {
25656  cimg::swap((*this)[indm],(*this)[mid]);
25657  if (is_permutations) cimg::swap(permutations[indm],permutations[mid]);
25658  }
25659  if ((*this)[mid]<(*this)[indM]) {
25660  cimg::swap((*this)[indM],(*this)[mid]);
25661  if (is_permutations) cimg::swap(permutations[indM],permutations[mid]);
25662  }
25663  if ((*this)[indm]<(*this)[mid]) {
25664  cimg::swap((*this)[indm],(*this)[mid]);
25665  if (is_permutations) cimg::swap(permutations[indm],permutations[mid]);
25666  }
25667  }
25668  if (indM - indm>=3) {
25669  const T pivot = (*this)[mid];
25670  long i = indm, j = indM;
25671  if (is_increasing) {
25672  do {
25673  while ((*this)[i]<pivot) ++i;
25674  while ((*this)[j]>pivot) --j;
25675  if (i<=j) {
25676  if (is_permutations) cimg::swap(permutations[i],permutations[j]);
25677  cimg::swap((*this)[i++],(*this)[j--]);
25678  }
25679  } while (i<=j);
25680  } else {
25681  do {
25682  while ((*this)[i]>pivot) ++i;
25683  while ((*this)[j]<pivot) --j;
25684  if (i<=j) {
25685  if (is_permutations) cimg::swap(permutations[i],permutations[j]);
25686  cimg::swap((*this)[i++],(*this)[j--]);
25687  }
25688  } while (i<=j);
25689  }
25690  if (indm<j) _quicksort(indm,j,permutations,is_increasing,is_permutations);
25691  if (i<indM) _quicksort(i,indM,permutations,is_increasing,is_permutations);
25692  }
25693  }
25694  return *this;
25695  }
25696 
25698 
25715  template<typename t>
25716  const CImg<T>& SVD(CImg<t>& U, CImg<t>& S, CImg<t>& V, const bool sorting=true,
25717  const unsigned int max_iteration=40, const float lambda=0) const {
25718  if (is_empty()) { U.assign(); S.assign(); V.assign(); }
25719  else {
25720  U = *this;
25721  if (lambda!=0) {
25722  const unsigned int delta = std::min(U._width,U._height);
25723  for (unsigned int i = 0; i<delta; ++i) U(i,i) = (t)(U(i,i) + lambda);
25724  }
25725  if (S.size()<_width) S.assign(1,_width);
25726  if (V._width<_width || V._height<_height) V.assign(_width,_width);
25727  CImg<t> rv1(_width);
25728  t anorm = 0, c, f, g = 0, h, s, scale = 0;
25729  int l = 0, nm = 0;
25730 
25731  cimg_forX(U,i) {
25732  l = i + 1; rv1[i] = scale*g; g = s = scale = 0;
25733  if (i<height()) {
25734  for (int k = i; k<height(); ++k) scale+=cimg::abs(U(i,k));
25735  if (scale) {
25736  for (int k = i; k<height(); ++k) { U(i,k)/=scale; s+=U(i,k)*U(i,k); }
25737  f = U(i,i); g = (t)((f>=0?-1:1)*std::sqrt(s)); h=f*g-s; U(i,i) = f-g;
25738  for (int j = l; j<width(); ++j) {
25739  s = 0;
25740  for (int k=i; k<height(); ++k) s+=U(i,k)*U(j,k);
25741  f = s/h;
25742  for (int k = i; k<height(); ++k) U(j,k)+=f*U(i,k);
25743  }
25744  for (int k = i; k<height(); ++k) U(i,k)*=scale;
25745  }
25746  }
25747  S[i]=scale*g;
25748 
25749  g = s = scale = 0;
25750  if (i<height() && i!=width() - 1) {
25751  for (int k = l; k<width(); ++k) scale+=cimg::abs(U(k,i));
25752  if (scale) {
25753  for (int k = l; k<width(); ++k) { U(k,i)/= scale; s+=U(k,i)*U(k,i); }
25754  f = U(l,i); g = (t)((f>=0?-1:1)*std::sqrt(s)); h = f*g-s; U(l,i) = f-g;
25755  for (int k = l; k<width(); ++k) rv1[k]=U(k,i)/h;
25756  for (int j = l; j<height(); ++j) {
25757  s = 0;
25758  for (int k = l; k<width(); ++k) s+=U(k,j)*U(k,i);
25759  for (int k = l; k<width(); ++k) U(k,j)+=s*rv1[k];
25760  }
25761  for (int k = l; k<width(); ++k) U(k,i)*=scale;
25762  }
25763  }
25764  anorm = (t)std::max((float)anorm,(float)(cimg::abs(S[i]) + cimg::abs(rv1[i])));
25765  }
25766 
25767  for (int i = width() - 1; i>=0; --i) {
25768  if (i<width()-1) {
25769  if (g) {
25770  for (int j = l; j<width(); ++j) V(i,j) =(U(j,i)/U(l,i))/g;
25771  for (int j = l; j<width(); ++j) {
25772  s = 0;
25773  for (int k = l; k<width(); ++k) s+=U(k,i)*V(j,k);
25774  for (int k = l; k<width(); ++k) V(j,k)+=s*V(i,k);
25775  }
25776  }
25777  for (int j = l; j<width(); ++j) V(j,i) = V(i,j) = (t)0.0;
25778  }
25779  V(i,i) = (t)1.0; g = rv1[i]; l =